/// \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 {
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,
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.
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) { }
}
})
+DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
+ TRY_TO(TraverseDecl(D->getSpecialization()));
+ })
+
DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
DEF_TRAVERSE_DECL(ObjCClassDecl, {
def FriendTemplate : Decl;
def StaticAssert : Decl;
def Block : Decl, DeclContext;
+def ClassScopeFunctionSpecialization : Decl;
"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<
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,
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);
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) {
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.
= 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
+ 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);
}
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;
}
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
return 0;
}
+FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
+ return getASTContext().getClassScopeSpecializationPattern(this);
+}
+
const TemplateArgumentList *
FunctionDecl::getTemplateSpecializationArgs() const {
if (FunctionTemplateSpecializationInfo *Info
case UsingDirective:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
+ case ClassScopeFunctionSpecialization:
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
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;
// 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.
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);
} 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),
// 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;
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.
FunctionTemplateDecl *FunctionTemplate = 0;
bool isExplicitSpecialization = false;
bool isFunctionTemplateSpecialization = false;
+ bool isDependentClassScopeExplicitSpecialization = false;
if (!getLangOptions().CPlusPlus) {
// Determine whether the function was written with a
} 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))
}
// 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) &&
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;
}
}
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);
}
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:
// 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
Decl *
TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
- TemplateParameterList *TemplateParams) {
+ TemplateParameterList *TemplateParams,
+ bool IsClassScopeSpecialization) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
if (FunctionTemplate && !TemplateParams) {
}
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());
: Method);
if (isFriend)
Record->makeDeclVisibleInContext(DeclToAdd);
- else
+ else if (!IsClassScopeSpecialization)
Owner->addDecl(DeclToAdd);
}
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);
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.
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;
--- /dev/null
+// 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);
+}
+
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