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

21 files changed

+280
-26
lines changed

clang/include/clang/AST/ASTContext.h

+10
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

+5-1
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

+52
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

+4
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

+1
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

+3
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

+2-1
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

+4-1
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

+4-1
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

+20-1
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
}

clang/lib/AST/Decl.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -1922,13 +1922,17 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
19221922

19231923
switch (getTemplateSpecializationKind()) {
19241924
case TSK_Undeclared:
1925-
case TSK_ExplicitSpecialization:
19261925
case TSK_ExplicitInstantiationDefinition:
19271926
return false;
19281927

19291928
case TSK_ImplicitInstantiation:
19301929
return true;
19311930

1931+
// It is possible to instantiate TSK_ExplicitSpecialization kind
1932+
// if the FunctionDecl has a class scope specialization pattern.
1933+
case TSK_ExplicitSpecialization:
1934+
return getClassScopeSpecializationPattern() != 0;
1935+
19321936
case TSK_ExplicitInstantiationDeclaration:
19331937
// Handled below.
19341938
break;
@@ -1951,6 +1955,10 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
19511955
}
19521956

19531957
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
1958+
// Handle class scope explicit specialization special case.
1959+
if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
1960+
return getClassScopeSpecializationPattern();
1961+
19541962
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
19551963
while (Primary->getInstantiatedFromMemberTemplate()) {
19561964
// If we have hit a point where the user provided a specialization of
@@ -1976,6 +1984,10 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
19761984
return 0;
19771985
}
19781986

1987+
FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
1988+
return getASTContext().getClassScopeSpecializationPattern(this);
1989+
}
1990+
19791991
const TemplateArgumentList *
19801992
FunctionDecl::getTemplateSpecializationArgs() const {
19811993
if (FunctionTemplateSpecializationInfo *Info

clang/lib/AST/DeclBase.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
493493
case UsingDirective:
494494
case ClassTemplateSpecialization:
495495
case ClassTemplatePartialSpecialization:
496+
case ClassScopeFunctionSpecialization:
496497
case ObjCImplementation:
497498
case ObjCCategory:
498499
case ObjCCategoryImpl:

clang/lib/CodeGen/CGDecl.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
7070
case Decl::Friend:
7171
case Decl::FriendTemplate:
7272
case Decl::Block:
73+
case Decl::ClassScopeFunctionSpecialization:
7374
assert(0 && "Declaration should not be in declstmts!");
7475
case Decl::Function: // void X();
7576
case Decl::Record: // struct/union/class X;

clang/lib/Sema/SemaDecl.cpp

+35-9
Original file line numberDiff line numberDiff line change
@@ -1722,9 +1722,16 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
17221722
// Preserve triviality.
17231723
NewMethod->setTrivial(OldMethod->isTrivial());
17241724

1725+
// MSVC allows explicit template specialization at class scope:
1726+
// 2 CXMethodDecls referring to the same function will be injected.
1727+
// We don't want a redeclartion error.
1728+
bool IsClassScopeExplicitSpecialization =
1729+
OldMethod->isFunctionTemplateSpecialization() &&
1730+
NewMethod->isFunctionTemplateSpecialization();
17251731
bool isFriend = NewMethod->getFriendObjectKind();
17261732

1727-
if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) {
1733+
if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() &&
1734+
!IsClassScopeExplicitSpecialization) {
17281735
// -- Member function declarations with the same name and the
17291736
// same parameter types cannot be overloaded if any of them
17301737
// is a static member function declaration.
@@ -3226,6 +3233,7 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
32263233
Previous.clear();
32273234

32283235
bool Redeclaration = false;
3236+
bool AddToScope = true;
32293237
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
32303238
if (TemplateParamLists.size()) {
32313239
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
@@ -3236,7 +3244,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
32363244
} else if (R->isFunctionType()) {
32373245
New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
32383246
move(TemplateParamLists),
3239-
IsFunctionDefinition, Redeclaration);
3247+
IsFunctionDefinition, Redeclaration,
3248+
AddToScope);
32403249
} else {
32413250
New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
32423251
move(TemplateParamLists),
@@ -3248,7 +3257,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
32483257

32493258
// If this has an identifier and is not an invalid redeclaration or
32503259
// function template specialization, add it to the scope stack.
3251-
if (New->getDeclName() && !(Redeclaration && New->isInvalidDecl()))
3260+
if (New->getDeclName() && AddToScope &&
3261+
!(Redeclaration && New->isInvalidDecl()))
32523262
PushOnScopeChains(New, S);
32533263

32543264
return New;
@@ -4201,7 +4211,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
42014211
QualType R, TypeSourceInfo *TInfo,
42024212
LookupResult &Previous,
42034213
MultiTemplateParamsArg TemplateParamLists,
4204-
bool IsFunctionDefinition, bool &Redeclaration) {
4214+
bool IsFunctionDefinition, bool &Redeclaration,
4215+
bool &AddToScope) {
42054216
assert(R.getTypePtr()->isFunctionType());
42064217

42074218
// TODO: consider using NameInfo for diagnostic.
@@ -4266,6 +4277,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
42664277
FunctionTemplateDecl *FunctionTemplate = 0;
42674278
bool isExplicitSpecialization = false;
42684279
bool isFunctionTemplateSpecialization = false;
4280+
bool isDependentClassScopeExplicitSpecialization = false;
42694281

42704282
if (!getLangOptions().CPlusPlus) {
42714283
// Determine whether the function was written with a
@@ -4769,10 +4781,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
47694781
} else if (isFunctionTemplateSpecialization) {
47704782
if (CurContext->isDependentContext() && CurContext->isRecord()
47714783
&& !isFriend) {
4772-
Diag(NewFD->getLocation(), diag::err_function_specialization_in_class)
4784+
isDependentClassScopeExplicitSpecialization = true;
4785+
Diag(NewFD->getLocation(), getLangOptions().Microsoft ?
4786+
diag::ext_function_specialization_in_class :
4787+
diag::err_function_specialization_in_class)
47734788
<< NewFD->getDeclName();
4774-
NewFD->setInvalidDecl();
4775-
return 0;
47764789
} else if (CheckFunctionTemplateSpecialization(NewFD,
47774790
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
47784791
Previous))
@@ -4802,8 +4815,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
48024815
}
48034816

48044817
// Perform semantic checking on the function declaration.
4805-
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
4806-
Redeclaration);
4818+
if (!isDependentClassScopeExplicitSpecialization)
4819+
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
4820+
Redeclaration);
48074821

48084822
assert((NewFD->isInvalidDecl() || !Redeclaration ||
48094823
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
@@ -4984,6 +4998,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
49844998
Context.setcudaConfigureCallDecl(NewFD);
49854999
}
49865000
}
5001+
5002+
// Here we have an function template explicit specialization at class scope.
5003+
// The actually specialization will be postponed to template instatiation
5004+
// time via the ClassScopeFunctionSpecializationDecl node.
5005+
if (isDependentClassScopeExplicitSpecialization) {
5006+
ClassScopeFunctionSpecializationDecl *NewSpec =
5007+
ClassScopeFunctionSpecializationDecl::Create(
5008+
Context, CurContext, SourceLocation(),
5009+
cast<CXXMethodDecl>(NewFD));
5010+
CurContext->addDecl(NewSpec);
5011+
AddToScope = false;
5012+
}
49875013

49885014
return NewFD;
49895015
}

clang/lib/Sema/SemaDeclCXX.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -8652,10 +8652,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
86528652
}
86538653

86548654
bool Redeclaration = false;
8655+
bool AddToScope = true;
86558656
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous,
86568657
move(TemplateParams),
86578658
IsDefinition,
8658-
Redeclaration);
8659+
Redeclaration, AddToScope);
86598660
if (!ND) return 0;
86608661

86618662
assert(ND->getDeclContext() == DC);

clang/lib/Sema/SemaTemplate.cpp

+12-3
Original file line numberDiff line numberDiff line change
@@ -4511,9 +4511,18 @@ static bool CheckTemplateSpecializationScope(Sema &S,
45114511
}
45124512

45134513
if (S.CurContext->isRecord() && !IsPartialSpecialization) {
4514-
S.Diag(Loc, diag::err_template_spec_decl_class_scope)
4515-
<< Specialized;
4516-
return true;
4514+
if (S.getLangOptions().Microsoft) {
4515+
// Do not warn for class scope explicit specialization during
4516+
// instantiation, warning was already emitted during pattern
4517+
// semantic analysis.
4518+
if (!S.ActiveTemplateInstantiations.size())
4519+
S.Diag(Loc, diag::ext_function_specialization_in_class)
4520+
<< Specialized;
4521+
} else {
4522+
S.Diag(Loc, diag::err_template_spec_decl_class_scope)
4523+
<< Specialized;
4524+
return true;
4525+
}
45174526
}
45184527

45194528
// C++ [temp.class.spec]p6:

0 commit comments

Comments
 (0)