forked from OSchip/llvm-project
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
This commit is contained in:
parent
ae13df60a6
commit
00c7e6ceb1
|
@ -152,6 +152,11 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||||
/// \brief Mapping from __block VarDecls to their copy initialization expr.
|
/// \brief Mapping from __block VarDecls to their copy initialization expr.
|
||||||
llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
|
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
|
/// \brief Representation of a "canonical" template template parameter that
|
||||||
/// is used in canonical template names.
|
/// is used in canonical template names.
|
||||||
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
|
||||||
|
@ -382,6 +387,11 @@ public:
|
||||||
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
|
||||||
const VarDecl *Var);
|
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
|
/// \brief Note that the static data member \p Inst is an instantiation of
|
||||||
/// the static data member template \p Tmpl of a class template.
|
/// the static data member template \p Tmpl of a class template.
|
||||||
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
||||||
|
|
|
@ -1852,6 +1852,10 @@ public:
|
||||||
return getPrimaryTemplate() != 0;
|
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,
|
/// \brief If this function is actually a function template specialization,
|
||||||
/// retrieve information about this function template specialization.
|
/// retrieve information about this function template specialization.
|
||||||
/// Otherwise, returns NULL.
|
/// Otherwise, returns NULL.
|
||||||
|
|
|
@ -2097,6 +2097,58 @@ public:
|
||||||
friend class ASTDeclWriter;
|
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
|
/// Implementation of inline functions that require the template declarations
|
||||||
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
|
||||||
: Function(FTD) { }
|
: Function(FTD) { }
|
||||||
|
|
|
@ -1114,6 +1114,10 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
|
||||||
|
TRY_TO(TraverseDecl(D->getSpecialization()));
|
||||||
|
})
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
|
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
|
||||||
|
|
||||||
DEF_TRAVERSE_DECL(ObjCClassDecl, {
|
DEF_TRAVERSE_DECL(ObjCClassDecl, {
|
||||||
|
|
|
@ -74,3 +74,4 @@ def Friend : Decl;
|
||||||
def FriendTemplate : Decl;
|
def FriendTemplate : Decl;
|
||||||
def StaticAssert : Decl;
|
def StaticAssert : Decl;
|
||||||
def Block : Decl, DeclContext;
|
def Block : Decl, DeclContext;
|
||||||
|
def ClassScopeFunctionSpecialization : Decl;
|
||||||
|
|
|
@ -2028,6 +2028,9 @@ def err_not_class_template_specialization : Error<
|
||||||
"parameter}0">;
|
"parameter}0">;
|
||||||
def err_function_specialization_in_class : Error<
|
def err_function_specialization_in_class : Error<
|
||||||
"cannot specialize a function %0 within class scope">;
|
"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">,
|
||||||
|
InGroup<Microsoft>;
|
||||||
def ext_explicit_specialization_storage_class : ExtWarn<
|
def ext_explicit_specialization_storage_class : ExtWarn<
|
||||||
"explicit specialization cannot have a storage class">;
|
"explicit specialization cannot have a storage class">;
|
||||||
def err_explicit_specialization_inconsistent_storage_class : Error<
|
def err_explicit_specialization_inconsistent_storage_class : Error<
|
||||||
|
|
|
@ -1002,7 +1002,8 @@ public:
|
||||||
LookupResult &Previous,
|
LookupResult &Previous,
|
||||||
MultiTemplateParamsArg TemplateParamLists,
|
MultiTemplateParamsArg TemplateParamLists,
|
||||||
bool IsFunctionDefinition,
|
bool IsFunctionDefinition,
|
||||||
bool &Redeclaration);
|
bool &Redeclaration,
|
||||||
|
bool &AddToScope);
|
||||||
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
|
bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
|
||||||
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
|
void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
|
||||||
void CheckFunctionDeclaration(Scope *S,
|
void CheckFunctionDeclaration(Scope *S,
|
||||||
|
|
|
@ -350,7 +350,8 @@ namespace clang {
|
||||||
TemplateParameterList *TemplateParams = 0);
|
TemplateParameterList *TemplateParams = 0);
|
||||||
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
|
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
|
||||||
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
|
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
|
||||||
TemplateParameterList *TemplateParams = 0);
|
TemplateParameterList *TemplateParams = 0,
|
||||||
|
bool IsClassScopeSpecialization = false);
|
||||||
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
|
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
|
||||||
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
|
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
|
||||||
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
|
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
|
||||||
|
@ -367,6 +368,8 @@ namespace clang {
|
||||||
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
|
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
|
||||||
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
|
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
|
||||||
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
|
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
|
||||||
|
Decl *VisitClassScopeFunctionSpecializationDecl(
|
||||||
|
ClassScopeFunctionSpecializationDecl *D);
|
||||||
|
|
||||||
// Base case. FIXME: Remove once we can instantiate everything.
|
// Base case. FIXME: Remove once we can instantiate everything.
|
||||||
Decl *VisitDecl(Decl *D) {
|
Decl *VisitDecl(Decl *D) {
|
||||||
|
|
|
@ -826,7 +826,10 @@ namespace clang {
|
||||||
DECL_INDIRECTFIELD,
|
DECL_INDIRECTFIELD,
|
||||||
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
|
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
|
||||||
/// non-type template parameter pack.
|
/// 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.
|
/// \brief Record codes for each kind of statement or expression.
|
||||||
|
|
|
@ -518,6 +518,24 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
||||||
= new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
|
= 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 *
|
NamedDecl *
|
||||||
ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
|
ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
|
||||||
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
|
llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
|
||||||
|
@ -6439,5 +6457,6 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
|
||||||
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
|
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
|
||||||
+ llvm::capacity_in_bytes(OverriddenMethods)
|
+ llvm::capacity_in_bytes(OverriddenMethods)
|
||||||
+ llvm::capacity_in_bytes(Types)
|
+ llvm::capacity_in_bytes(Types)
|
||||||
+ llvm::capacity_in_bytes(VariableArrayTypes);
|
+ llvm::capacity_in_bytes(VariableArrayTypes)
|
||||||
|
+ llvm::capacity_in_bytes(ClassScopeSpecilizationPattern);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1922,13 +1922,17 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
|
||||||
|
|
||||||
switch (getTemplateSpecializationKind()) {
|
switch (getTemplateSpecializationKind()) {
|
||||||
case TSK_Undeclared:
|
case TSK_Undeclared:
|
||||||
case TSK_ExplicitSpecialization:
|
|
||||||
case TSK_ExplicitInstantiationDefinition:
|
case TSK_ExplicitInstantiationDefinition:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case TSK_ImplicitInstantiation:
|
case TSK_ImplicitInstantiation:
|
||||||
return true;
|
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:
|
case TSK_ExplicitInstantiationDeclaration:
|
||||||
// Handled below.
|
// Handled below.
|
||||||
break;
|
break;
|
||||||
|
@ -1951,6 +1955,10 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
|
FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
|
||||||
|
// Handle class scope explicit specialization special case.
|
||||||
|
if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||||
|
return getClassScopeSpecializationPattern();
|
||||||
|
|
||||||
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
|
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
|
||||||
while (Primary->getInstantiatedFromMemberTemplate()) {
|
while (Primary->getInstantiatedFromMemberTemplate()) {
|
||||||
// If we have hit a point where the user provided a specialization of
|
// If we have hit a point where the user provided a specialization of
|
||||||
|
@ -1976,6 +1984,10 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
|
||||||
|
return getASTContext().getClassScopeSpecializationPattern(this);
|
||||||
|
}
|
||||||
|
|
||||||
const TemplateArgumentList *
|
const TemplateArgumentList *
|
||||||
FunctionDecl::getTemplateSpecializationArgs() const {
|
FunctionDecl::getTemplateSpecializationArgs() const {
|
||||||
if (FunctionTemplateSpecializationInfo *Info
|
if (FunctionTemplateSpecializationInfo *Info
|
||||||
|
|
|
@ -493,6 +493,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
||||||
case UsingDirective:
|
case UsingDirective:
|
||||||
case ClassTemplateSpecialization:
|
case ClassTemplateSpecialization:
|
||||||
case ClassTemplatePartialSpecialization:
|
case ClassTemplatePartialSpecialization:
|
||||||
|
case ClassScopeFunctionSpecialization:
|
||||||
case ObjCImplementation:
|
case ObjCImplementation:
|
||||||
case ObjCCategory:
|
case ObjCCategory:
|
||||||
case ObjCCategoryImpl:
|
case ObjCCategoryImpl:
|
||||||
|
|
|
@ -70,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
||||||
case Decl::Friend:
|
case Decl::Friend:
|
||||||
case Decl::FriendTemplate:
|
case Decl::FriendTemplate:
|
||||||
case Decl::Block:
|
case Decl::Block:
|
||||||
|
case Decl::ClassScopeFunctionSpecialization:
|
||||||
assert(0 && "Declaration should not be in declstmts!");
|
assert(0 && "Declaration should not be in declstmts!");
|
||||||
case Decl::Function: // void X();
|
case Decl::Function: // void X();
|
||||||
case Decl::Record: // struct/union/class X;
|
case Decl::Record: // struct/union/class X;
|
||||||
|
|
|
@ -1722,9 +1722,16 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
|
||||||
// Preserve triviality.
|
// Preserve triviality.
|
||||||
NewMethod->setTrivial(OldMethod->isTrivial());
|
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();
|
bool isFriend = NewMethod->getFriendObjectKind();
|
||||||
|
|
||||||
if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) {
|
if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() &&
|
||||||
|
!IsClassScopeExplicitSpecialization) {
|
||||||
// -- Member function declarations with the same name and the
|
// -- Member function declarations with the same name and the
|
||||||
// same parameter types cannot be overloaded if any of them
|
// same parameter types cannot be overloaded if any of them
|
||||||
// is a static member function declaration.
|
// is a static member function declaration.
|
||||||
|
@ -3226,6 +3233,7 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
||||||
Previous.clear();
|
Previous.clear();
|
||||||
|
|
||||||
bool Redeclaration = false;
|
bool Redeclaration = false;
|
||||||
|
bool AddToScope = true;
|
||||||
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||||
if (TemplateParamLists.size()) {
|
if (TemplateParamLists.size()) {
|
||||||
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
|
Diag(D.getIdentifierLoc(), diag::err_template_typedef);
|
||||||
|
@ -3236,7 +3244,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
||||||
} else if (R->isFunctionType()) {
|
} else if (R->isFunctionType()) {
|
||||||
New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
|
New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
|
||||||
move(TemplateParamLists),
|
move(TemplateParamLists),
|
||||||
IsFunctionDefinition, Redeclaration);
|
IsFunctionDefinition, Redeclaration,
|
||||||
|
AddToScope);
|
||||||
} else {
|
} else {
|
||||||
New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
|
New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
|
||||||
move(TemplateParamLists),
|
move(TemplateParamLists),
|
||||||
|
@ -3248,7 +3257,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
||||||
|
|
||||||
// If this has an identifier and is not an invalid redeclaration or
|
// If this has an identifier and is not an invalid redeclaration or
|
||||||
// function template specialization, add it to the scope stack.
|
// 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);
|
PushOnScopeChains(New, S);
|
||||||
|
|
||||||
return New;
|
return New;
|
||||||
|
@ -4201,7 +4211,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
QualType R, TypeSourceInfo *TInfo,
|
QualType R, TypeSourceInfo *TInfo,
|
||||||
LookupResult &Previous,
|
LookupResult &Previous,
|
||||||
MultiTemplateParamsArg TemplateParamLists,
|
MultiTemplateParamsArg TemplateParamLists,
|
||||||
bool IsFunctionDefinition, bool &Redeclaration) {
|
bool IsFunctionDefinition, bool &Redeclaration,
|
||||||
|
bool &AddToScope) {
|
||||||
assert(R.getTypePtr()->isFunctionType());
|
assert(R.getTypePtr()->isFunctionType());
|
||||||
|
|
||||||
// TODO: consider using NameInfo for diagnostic.
|
// TODO: consider using NameInfo for diagnostic.
|
||||||
|
@ -4266,6 +4277,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
FunctionTemplateDecl *FunctionTemplate = 0;
|
FunctionTemplateDecl *FunctionTemplate = 0;
|
||||||
bool isExplicitSpecialization = false;
|
bool isExplicitSpecialization = false;
|
||||||
bool isFunctionTemplateSpecialization = false;
|
bool isFunctionTemplateSpecialization = false;
|
||||||
|
bool isDependentClassScopeExplicitSpecialization = false;
|
||||||
|
|
||||||
if (!getLangOptions().CPlusPlus) {
|
if (!getLangOptions().CPlusPlus) {
|
||||||
// Determine whether the function was written with a
|
// Determine whether the function was written with a
|
||||||
|
@ -4769,10 +4781,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
} else if (isFunctionTemplateSpecialization) {
|
} else if (isFunctionTemplateSpecialization) {
|
||||||
if (CurContext->isDependentContext() && CurContext->isRecord()
|
if (CurContext->isDependentContext() && CurContext->isRecord()
|
||||||
&& !isFriend) {
|
&& !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->getDeclName();
|
||||||
NewFD->setInvalidDecl();
|
|
||||||
return 0;
|
|
||||||
} else if (CheckFunctionTemplateSpecialization(NewFD,
|
} else if (CheckFunctionTemplateSpecialization(NewFD,
|
||||||
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
|
(HasExplicitTemplateArgs ? &TemplateArgs : 0),
|
||||||
Previous))
|
Previous))
|
||||||
|
@ -4802,8 +4815,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform semantic checking on the function declaration.
|
// Perform semantic checking on the function declaration.
|
||||||
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
|
if (!isDependentClassScopeExplicitSpecialization)
|
||||||
Redeclaration);
|
CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
|
||||||
|
Redeclaration);
|
||||||
|
|
||||||
assert((NewFD->isInvalidDecl() || !Redeclaration ||
|
assert((NewFD->isInvalidDecl() || !Redeclaration ||
|
||||||
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
|
Previous.getResultKind() != LookupResult::FoundOverloaded) &&
|
||||||
|
@ -4985,6 +4999,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
return NewFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8652,10 +8652,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Redeclaration = false;
|
bool Redeclaration = false;
|
||||||
|
bool AddToScope = true;
|
||||||
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous,
|
NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous,
|
||||||
move(TemplateParams),
|
move(TemplateParams),
|
||||||
IsDefinition,
|
IsDefinition,
|
||||||
Redeclaration);
|
Redeclaration, AddToScope);
|
||||||
if (!ND) return 0;
|
if (!ND) return 0;
|
||||||
|
|
||||||
assert(ND->getDeclContext() == DC);
|
assert(ND->getDeclContext() == DC);
|
||||||
|
|
|
@ -4511,9 +4511,18 @@ static bool CheckTemplateSpecializationScope(Sema &S,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S.CurContext->isRecord() && !IsPartialSpecialization) {
|
if (S.CurContext->isRecord() && !IsPartialSpecialization) {
|
||||||
S.Diag(Loc, diag::err_template_spec_decl_class_scope)
|
if (S.getLangOptions().Microsoft) {
|
||||||
<< Specialized;
|
// Do not warn for class scope explicit specialization during
|
||||||
return true;
|
// 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:
|
// C++ [temp.class.spec]p6:
|
||||||
|
|
|
@ -98,8 +98,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
|
||||||
// Add template arguments from a function template specialization.
|
// Add template arguments from a function template specialization.
|
||||||
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
|
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
|
||||||
if (!RelativeToPrimary &&
|
if (!RelativeToPrimary &&
|
||||||
Function->getTemplateSpecializationKind()
|
(Function->getTemplateSpecializationKind() ==
|
||||||
== TSK_ExplicitSpecialization)
|
TSK_ExplicitSpecialization &&
|
||||||
|
!Function->getClassScopeSpecializationPattern()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (const TemplateArgumentList *TemplateArgs
|
if (const TemplateArgumentList *TemplateArgs
|
||||||
|
|
|
@ -1288,7 +1288,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
|
||||||
|
|
||||||
Decl *
|
Decl *
|
||||||
TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
||||||
TemplateParameterList *TemplateParams) {
|
TemplateParameterList *TemplateParams,
|
||||||
|
bool IsClassScopeSpecialization) {
|
||||||
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
|
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
|
||||||
void *InsertPos = 0;
|
void *InsertPos = 0;
|
||||||
if (FunctionTemplate && !TemplateParams) {
|
if (FunctionTemplate && !TemplateParams) {
|
||||||
|
@ -1493,7 +1494,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Redeclaration = false;
|
bool Redeclaration = false;
|
||||||
SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration);
|
if (!IsClassScopeSpecialization)
|
||||||
|
SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration);
|
||||||
|
|
||||||
if (D->isPure())
|
if (D->isPure())
|
||||||
SemaRef.CheckPureMethod(Method, SourceRange());
|
SemaRef.CheckPureMethod(Method, SourceRange());
|
||||||
|
@ -1512,7 +1514,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
||||||
: Method);
|
: Method);
|
||||||
if (isFriend)
|
if (isFriend)
|
||||||
Record->makeDeclVisibleInContext(DeclToAdd);
|
Record->makeDeclVisibleInContext(DeclToAdd);
|
||||||
else
|
else if (!IsClassScopeSpecialization)
|
||||||
Owner->addDecl(DeclToAdd);
|
Owner->addDecl(DeclToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1907,6 +1909,29 @@ Decl * TemplateDeclInstantiator
|
||||||
return UD;
|
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,
|
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||||
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
|
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
|
||||||
|
@ -2335,8 +2360,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
||||||
if (Function->isInvalidDecl() || Function->isDefined())
|
if (Function->isInvalidDecl() || Function->isDefined())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Never instantiate an explicit specialization.
|
// Never instantiate an explicit specialization except if it is a class scope
|
||||||
if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
// explicit specialization.
|
||||||
|
if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
|
||||||
|
!Function->getClassScopeSpecializationPattern())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Find the function body that we'll be substituting.
|
// Find the function body that we'll be substituting.
|
||||||
|
|
|
@ -1568,6 +1568,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
||||||
D = ClassTemplatePartialSpecializationDecl::Create(*Context,
|
D = ClassTemplatePartialSpecializationDecl::Create(*Context,
|
||||||
Decl::EmptyShell());
|
Decl::EmptyShell());
|
||||||
break;
|
break;
|
||||||
|
case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
|
||||||
|
D = ClassScopeFunctionSpecializationDecl::Create(*Context,
|
||||||
|
Decl::EmptyShell());
|
||||||
|
break;
|
||||||
case DECL_FUNCTION_TEMPLATE:
|
case DECL_FUNCTION_TEMPLATE:
|
||||||
D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell());
|
D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -4048,6 +4048,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
|
||||||
case Decl::StaticAssert:
|
case Decl::StaticAssert:
|
||||||
case Decl::Block:
|
case Decl::Block:
|
||||||
case Decl::Label: // FIXME: Is this right??
|
case Decl::Label: // FIXME: Is this right??
|
||||||
|
case Decl::ClassScopeFunctionSpecialization:
|
||||||
return C;
|
return C;
|
||||||
|
|
||||||
// Declaration kinds that don't make any sense here, but are
|
// Declaration kinds that don't make any sense here, but are
|
||||||
|
|
Loading…
Reference in New Issue