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.
|
||||
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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -1852,6 +1852,10 @@ public:
|
|||
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.
|
||||
|
|
|
@ -2097,6 +2097,58 @@ public:
|
|||
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) { }
|
||||
|
|
|
@ -1114,6 +1114,10 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
|
|||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
|
||||
TRY_TO(TraverseDecl(D->getSpecialization()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
|
||||
|
||||
DEF_TRAVERSE_DECL(ObjCClassDecl, {
|
||||
|
|
|
@ -74,3 +74,4 @@ def Friend : Decl;
|
|||
def FriendTemplate : Decl;
|
||||
def StaticAssert : Decl;
|
||||
def Block : Decl, DeclContext;
|
||||
def ClassScopeFunctionSpecialization : Decl;
|
||||
|
|
|
@ -2028,6 +2028,9 @@ def err_not_class_template_specialization : Error<
|
|||
"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">,
|
||||
InGroup<Microsoft>;
|
||||
def ext_explicit_specialization_storage_class : ExtWarn<
|
||||
"explicit specialization cannot have a storage class">;
|
||||
def err_explicit_specialization_inconsistent_storage_class : Error<
|
||||
|
|
|
@ -1002,7 +1002,8 @@ public:
|
|||
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,
|
||||
|
|
|
@ -350,7 +350,8 @@ namespace clang {
|
|||
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 @@ namespace clang {
|
|||
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) {
|
||||
|
|
|
@ -826,7 +826,10 @@ namespace clang {
|
|||
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.
|
||||
|
|
|
@ -518,6 +518,24 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
|
|||
= 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 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
|
|||
+ 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);
|
||||
}
|
||||
|
|
|
@ -1922,13 +1922,17 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
|
|||
|
||||
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 @@ bool FunctionDecl::isImplicitlyInstantiable() const {
|
|||
}
|
||||
|
||||
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 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
|
||||
return getASTContext().getClassScopeSpecializationPattern(this);
|
||||
}
|
||||
|
||||
const TemplateArgumentList *
|
||||
FunctionDecl::getTemplateSpecializationArgs() const {
|
||||
if (FunctionTemplateSpecializationInfo *Info
|
||||
|
|
|
@ -493,6 +493,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
|
|||
case UsingDirective:
|
||||
case ClassTemplateSpecialization:
|
||||
case ClassTemplatePartialSpecialization:
|
||||
case ClassScopeFunctionSpecialization:
|
||||
case ObjCImplementation:
|
||||
case ObjCCategory:
|
||||
case ObjCCategoryImpl:
|
||||
|
|
|
@ -70,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
|
|||
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;
|
||||
|
|
|
@ -1722,9 +1722,16 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
|
|||
// 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 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
|||
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 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
|||
} 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 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
|||
|
||||
// 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 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
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 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
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 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
} 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 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
}
|
||||
|
||||
// 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) &&
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -8652,10 +8652,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition,
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -4511,9 +4511,18 @@ static bool CheckTemplateSpecializationScope(Sema &S,
|
|||
}
|
||||
|
||||
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:
|
||||
|
|
|
@ -98,8 +98,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D,
|
|||
// 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
|
||||
|
|
|
@ -1288,7 +1288,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
|
|||
|
||||
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 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
|||
}
|
||||
|
||||
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 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
|||
: Method);
|
||||
if (isFriend)
|
||||
Record->makeDeclVisibleInContext(DeclToAdd);
|
||||
else
|
||||
else if (!IsClassScopeSpecialization)
|
||||
Owner->addDecl(DeclToAdd);
|
||||
}
|
||||
|
||||
|
@ -1907,6 +1909,29 @@ Decl * TemplateDeclInstantiator
|
|||
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 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
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.
|
||||
|
|
|
@ -1568,6 +1568,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
|||
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;
|
||||
|
|
|
@ -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::Block:
|
||||
case Decl::Label: // FIXME: Is this right??
|
||||
case Decl::ClassScopeFunctionSpecialization:
|
||||
return C;
|
||||
|
||||
// Declaration kinds that don't make any sense here, but are
|
||||
|
|
Loading…
Reference in New Issue