Skip to content

Commit 00c7e6c

Browse files
committed
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. llvm-svn: 137573
1 parent ae13df6 commit 00c7e6c

File tree

21 files changed

+280
-26
lines changed

21 files changed

+280
-26
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
152152
/// \brief Mapping from __block VarDecls to their copy initialization expr.
153153
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
154154

155+
/// \brief Mapping from class scope functions specialization to their
156+
/// templateS pattern.
157+
llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
158+
ClassScopeSpecilizationPattern;
159+
155160
/// \brief Representation of a "canonical" template template parameter that
156161
/// is used in canonical template names.
157162
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
@@ -382,6 +387,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
382387
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
383388
const VarDecl *Var);
384389

390+
FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
391+
392+
void setClassScopeSpecializationPattern(FunctionDecl *FD,
393+
FunctionDecl *Pattern);
394+
385395
/// \brief Note that the static data member \p Inst is an instantiation of
386396
/// the static data member template \p Tmpl of a class template.
387397
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,

clang/include/clang/AST/Decl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1851,7 +1851,11 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
18511851
bool isFunctionTemplateSpecialization() const {
18521852
return getPrimaryTemplate() != 0;
18531853
}
1854-
1854+
1855+
/// \brief Retrieve the class scope template pattern that this function
1856+
/// template specialization is instantiated from.
1857+
FunctionDecl *getClassScopeSpecializationPattern() const;
1858+
18551859
/// \brief If this function is actually a function template specialization,
18561860
/// retrieve information about this function template specialization.
18571861
/// Otherwise, returns NULL.

clang/include/clang/AST/DeclTemplate.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,6 +2097,58 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl,
20972097
friend class ASTDeclWriter;
20982098
};
20992099

2100+
/// Declaration of a function specialization at template class scope.
2101+
/// This is a non standard extension needed to support MSVC.
2102+
/// For example:
2103+
/// template <class T>
2104+
/// class A {
2105+
/// template <class U> void foo(U a) { }
2106+
/// template<> void foo(int a) { }
2107+
/// }
2108+
///
2109+
/// "template<> foo(int a)" will be saved in Specialization as a normal
2110+
/// CXXMethodDecl. Then during an instantiation of class A, it will be
2111+
/// transformed into an actual function specialization.
2112+
class ClassScopeFunctionSpecializationDecl : public Decl {
2113+
private:
2114+
ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
2115+
CXXMethodDecl *FD)
2116+
: Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
2117+
Specialization(FD) {}
2118+
2119+
ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
2120+
: Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
2121+
2122+
CXXMethodDecl *Specialization;
2123+
2124+
public:
2125+
CXXMethodDecl *getSpecialization() const { return Specialization; }
2126+
2127+
static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C,
2128+
DeclContext *DC,
2129+
SourceLocation Loc,
2130+
CXXMethodDecl *FD) {
2131+
return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD);
2132+
}
2133+
2134+
static ClassScopeFunctionSpecializationDecl *Create(ASTContext &Context,
2135+
EmptyShell Empty) {
2136+
return new (Context)ClassScopeFunctionSpecializationDecl(0,
2137+
SourceLocation(), 0);
2138+
}
2139+
// Implement isa/cast/dyncast/etc.
2140+
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
2141+
static bool classofKind(Kind K) {
2142+
return K == Decl::ClassScopeFunctionSpecialization;
2143+
}
2144+
static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
2145+
return true;
2146+
}
2147+
2148+
friend class ASTDeclReader;
2149+
friend class ASTDeclWriter;
2150+
};
2151+
21002152
/// Implementation of inline functions that require the template declarations
21012153
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
21022154
: Function(FTD) { }

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,10 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
11141114
}
11151115
})
11161116

1117+
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
1118+
TRY_TO(TraverseDecl(D->getSpecialization()));
1119+
})
1120+
11171121
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
11181122

11191123
DEF_TRAVERSE_DECL(ObjCClassDecl, {

clang/include/clang/Basic/DeclNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,4 @@ def Friend : Decl;
7474
def FriendTemplate : Decl;
7575
def StaticAssert : Decl;
7676
def Block : Decl, DeclContext;
77+
def ClassScopeFunctionSpecialization : Decl;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,6 +2028,9 @@ def err_not_class_template_specialization : Error<
20282028
"parameter}0">;
20292029
def err_function_specialization_in_class : Error<
20302030
"cannot specialize a function %0 within class scope">;
2031+
def ext_function_specialization_in_class : ExtWarn<
2032+
"explicit specialization of %0 within class scope in a Microsoft extension">,
2033+
InGroup<Microsoft>;
20312034
def ext_explicit_specialization_storage_class : ExtWarn<
20322035
"explicit specialization cannot have a storage class">;
20332036
def err_explicit_specialization_inconsistent_storage_class : Error<

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1002,7 +1002,8 @@ class Sema {
10021002
LookupResult &Previous,
10031003
MultiTemplateParamsArg TemplateParamLists,
10041004
bool IsFunctionDefinition,
1005-
bool &Redeclaration);
1005+
bool &Redeclaration,
1006+
bool &AddToScope);
10061007
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
10071008
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
10081009
void CheckFunctionDeclaration(Scope *S,

clang/include/clang/Sema/Template.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,8 @@ namespace clang {
350350
TemplateParameterList *TemplateParams = 0);
351351
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
352352
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
353-
TemplateParameterList *TemplateParams = 0);
353+
TemplateParameterList *TemplateParams = 0,
354+
bool IsClassScopeSpecialization = false);
354355
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
355356
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
356357
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
@@ -367,6 +368,8 @@ namespace clang {
367368
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
368369
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
369370
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
371+
Decl *VisitClassScopeFunctionSpecializationDecl(
372+
ClassScopeFunctionSpecializationDecl *D);
370373

371374
// Base case. FIXME: Remove once we can instantiate everything.
372375
Decl *VisitDecl(Decl *D) {

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,10 @@ namespace clang {
826826
DECL_INDIRECTFIELD,
827827
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
828828
/// non-type template parameter pack.
829-
DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK
829+
DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
830+
/// \brief A ClassScopeFunctionSpecializationDecl record a class scope
831+
/// function specialization. (Microsoft extension).
832+
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION
830833
};
831834

832835
/// \brief Record codes for each kind of statement or expression.

clang/lib/AST/ASTContext.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,24 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
518518
= new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
519519
}
520520

521+
FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
522+
const FunctionDecl *FD){
523+
assert(FD && "Specialization is 0");
524+
llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos
525+
= ClassScopeSpecilizationPattern.find(FD);
526+
if (Pos == ClassScopeSpecilizationPattern.end())
527+
return 0;
528+
529+
return Pos->second;
530+
}
531+
532+
void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD,
533+
FunctionDecl *Pattern) {
534+
assert(FD && "Specialization is 0");
535+
assert(Pattern && "Class scope specialization pattern is 0");
536+
ClassScopeSpecilizationPattern[FD] = Pattern;
537+
}
538+
521539
NamedDecl *
522540
ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
523541
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
@@ -6439,5 +6457,6 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
64396457
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
64406458
+ llvm::capacity_in_bytes(OverriddenMethods)
64416459
+ llvm::capacity_in_bytes(Types)
6442-
+ llvm::capacity_in_bytes(VariableArrayTypes);
6460+
+ llvm::capacity_in_bytes(VariableArrayTypes)
6461+
+ llvm::capacity_in_bytes(ClassScopeSpecilizationPattern);
64436462
}

0 commit comments

Comments
 (0)