forked from OSchip/llvm-project
Improve the AST representation and semantic analysis for extern
templates. We now distinguish between an explicit instantiation declaration and an explicit instantiation definition, and know not to instantiate explicit instantiation declarations. Unfortunately, there is some remaining confusion w.r.t. instantiation of out-of-line member function definitions that causes trouble here. llvm-svn: 81053
This commit is contained in:
parent
21d15aa591
commit
34ec2ef159
|
@ -715,6 +715,29 @@ public:
|
|||
static bool classof(const OriginalParmVarDecl *D) { return true; }
|
||||
};
|
||||
|
||||
// \brief Describes the kind of template specialization that a
|
||||
// particular template specialization declaration represents.
|
||||
enum TemplateSpecializationKind {
|
||||
/// This template specialization was formed from a template-id but
|
||||
/// has not yet been declared, defined, or instantiated.
|
||||
TSK_Undeclared = 0,
|
||||
/// This template specialization was implicitly instantiated from a
|
||||
/// template. (C++ [temp.inst]).
|
||||
TSK_ImplicitInstantiation,
|
||||
/// This template specialization was declared or defined by an
|
||||
/// explicit specialization (C++ [temp.expl.spec]) or partial
|
||||
/// specialization (C++ [temp.class.spec]).
|
||||
TSK_ExplicitSpecialization,
|
||||
/// This template specialization was instantiated from a template
|
||||
/// due to an explicit instantiation declaration request
|
||||
/// (C++0x [temp.explicit]).
|
||||
TSK_ExplicitInstantiationDeclaration,
|
||||
/// This template specialization was instantiated from a template
|
||||
/// due to an explicit instantiation definition request
|
||||
/// (C++ [temp.explicit]).
|
||||
TSK_ExplicitInstantiationDefinition
|
||||
};
|
||||
|
||||
/// FunctionDecl - An instance of this class is created to represent a
|
||||
/// function declaration or definition.
|
||||
///
|
||||
|
@ -1077,13 +1100,13 @@ public:
|
|||
const TemplateArgumentList *TemplateArgs,
|
||||
void *InsertPos);
|
||||
|
||||
/// \brief Determine whether this is an explicit specialization of a
|
||||
/// function template or a member function of a class template.
|
||||
bool isExplicitSpecialization() const;
|
||||
/// \brief Determine what kind of template instantiation this function
|
||||
/// represents.
|
||||
TemplateSpecializationKind getTemplateSpecializationKind() const;
|
||||
|
||||
/// \brief Note that this is an explicit specialization of a function template
|
||||
/// or a member function of a class template.
|
||||
void setExplicitSpecialization(bool ES);
|
||||
/// \brief Determine what kind of template instantiation this function
|
||||
/// represents.
|
||||
void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
|
|
|
@ -510,9 +510,8 @@ public:
|
|||
/// \brief The function template from which this function template
|
||||
/// specialization was generated.
|
||||
///
|
||||
/// The bit will be 0 for an implicit instantiation, 1 for an explicit
|
||||
/// specialization.
|
||||
llvm::PointerIntPair<FunctionTemplateDecl *, 1> Template;
|
||||
/// The two bits are contain the top 4 values of TemplateSpecializationKind.
|
||||
llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template;
|
||||
|
||||
/// \brief The template arguments used to produce the function template
|
||||
/// specialization from the function template.
|
||||
|
@ -521,13 +520,16 @@ public:
|
|||
/// \brief Retrieve the template from which this function was specialized.
|
||||
FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); }
|
||||
|
||||
/// \brief Determine whether this is an explicit specialization.
|
||||
bool isExplicitSpecialization() const { return Template.getInt(); }
|
||||
/// \brief Determine what kind of template specialization this is.
|
||||
TemplateSpecializationKind getTemplateSpecializationKind() const {
|
||||
return (TemplateSpecializationKind)(Template.getInt() + 1);
|
||||
}
|
||||
|
||||
/// \brief Set whether this is an explicit specialization or an implicit
|
||||
/// instantiation.
|
||||
void setExplicitSpecialization(bool ES) {
|
||||
Template.setInt(ES);
|
||||
/// \brief Set the template specialization kind.
|
||||
void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
|
||||
assert(TSK != TSK_Undeclared &&
|
||||
"Cannot encode TSK_Undeclared for a function template specialization");
|
||||
Template.setInt(TSK - 1);
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
|
@ -871,24 +873,6 @@ public:
|
|||
static bool classof(const TemplateTemplateParmDecl *D) { return true; }
|
||||
};
|
||||
|
||||
// \brief Describes the kind of template specialization that a
|
||||
// particular template specialization declaration represents.
|
||||
enum TemplateSpecializationKind {
|
||||
/// This template specialization was formed from a template-id but
|
||||
/// has not yet been declared, defined, or instantiated.
|
||||
TSK_Undeclared = 0,
|
||||
/// This template specialization was declared or defined by an
|
||||
/// explicit specialization (C++ [temp.expl.spec]) or partial
|
||||
/// specialization (C++ [temp.class.spec]).
|
||||
TSK_ExplicitSpecialization,
|
||||
/// This template specialization was implicitly instantiated from a
|
||||
/// template. (C++ [temp.inst]).
|
||||
TSK_ImplicitInstantiation,
|
||||
/// This template specialization was instantiated from a template
|
||||
/// due to an explicit instantiation request (C++ [temp.explicit]).
|
||||
TSK_ExplicitInstantiation
|
||||
};
|
||||
|
||||
/// \brief Represents a class template specialization, which refers to
|
||||
/// a class template with a given set of template arguments.
|
||||
///
|
||||
|
@ -927,7 +911,7 @@ class ClassTemplateSpecializationDecl
|
|||
|
||||
/// \brief The kind of specialization this declaration refers to.
|
||||
/// Really a value of type TemplateSpecializationKind.
|
||||
unsigned SpecializationKind : 2;
|
||||
unsigned SpecializationKind : 3;
|
||||
|
||||
protected:
|
||||
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
|
||||
|
@ -972,7 +956,8 @@ public:
|
|||
ClassTemplatePartialSpecializationDecl *>
|
||||
getInstantiatedFrom() const {
|
||||
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
|
||||
getSpecializationKind() != TSK_ExplicitInstantiation)
|
||||
getSpecializationKind() != TSK_ExplicitInstantiationDefinition &&
|
||||
getSpecializationKind() != TSK_ExplicitInstantiationDeclaration)
|
||||
return (ClassTemplateDecl*)0;
|
||||
|
||||
if (SpecializedPartialSpecialization *PartialSpec
|
||||
|
|
|
@ -640,7 +640,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
|||
|
||||
Info->Function = this;
|
||||
Info->Template.setPointer(Template);
|
||||
Info->Template.setInt(0); // Implicit instantiation, unless told otherwise
|
||||
Info->Template.setInt(TSK_ImplicitInstantiation - 1);
|
||||
Info->TemplateArguments = TemplateArgs;
|
||||
TemplateOrSpecialization = Info;
|
||||
|
||||
|
@ -649,24 +649,35 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
|||
Template->getSpecializations().InsertNode(Info, InsertPos);
|
||||
}
|
||||
|
||||
bool FunctionDecl::isExplicitSpecialization() const {
|
||||
// FIXME: check this property for explicit specializations of member
|
||||
// functions of class templates.
|
||||
FunctionTemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
||||
if (!Info)
|
||||
return false;
|
||||
|
||||
return Info->isExplicitSpecialization();
|
||||
}
|
||||
|
||||
void FunctionDecl::setExplicitSpecialization(bool ES) {
|
||||
// FIXME: set this property for explicit specializations of member functions
|
||||
// of class templates.
|
||||
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
|
||||
// For a function template specialization, query the specialization
|
||||
// information object.
|
||||
FunctionTemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
||||
if (Info)
|
||||
Info->setExplicitSpecialization(ES);
|
||||
return Info->getTemplateSpecializationKind();
|
||||
|
||||
if (!getInstantiatedFromMemberFunction())
|
||||
return TSK_Undeclared;
|
||||
|
||||
// Find the class template specialization corresponding to this instantiation
|
||||
// of a member function.
|
||||
const DeclContext *Parent = getDeclContext();
|
||||
while (Parent && !isa<ClassTemplateSpecializationDecl>(Parent))
|
||||
Parent = Parent->getParent();
|
||||
|
||||
if (!Parent)
|
||||
return TSK_Undeclared;
|
||||
|
||||
return cast<ClassTemplateSpecializationDecl>(Parent)->getSpecializationKind();
|
||||
}
|
||||
|
||||
void
|
||||
FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
|
||||
FunctionTemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
||||
assert(Info && "Not a function template specialization");
|
||||
Info->setTemplateSpecializationKind(TSK);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -251,8 +251,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
|
|||
// inline or static.
|
||||
CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal;
|
||||
if (Context.getLangOptions().CPlusPlus &&
|
||||
(FD->getPrimaryTemplate() || FD->getInstantiatedFromMemberFunction()) &&
|
||||
!FD->isExplicitSpecialization())
|
||||
FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
|
||||
External = CodeGenModule::GVA_TemplateInstantiation;
|
||||
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
|
||||
|
|
|
@ -3011,21 +3011,24 @@ public:
|
|||
InstantiateClass(SourceLocation PointOfInstantiation,
|
||||
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
bool ExplicitInstantiation,
|
||||
TemplateSpecializationKind TSK,
|
||||
bool Complain = true);
|
||||
|
||||
bool
|
||||
InstantiateClassTemplateSpecialization(
|
||||
ClassTemplateSpecializationDecl *ClassTemplateSpec,
|
||||
bool ExplicitInstantiation, bool Complain = true);
|
||||
TemplateSpecializationKind TSK,
|
||||
bool Complain = true);
|
||||
|
||||
void InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
||||
CXXRecordDecl *Instantiation,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
TemplateSpecializationKind TSK);
|
||||
|
||||
void InstantiateClassTemplateSpecializationMembers(
|
||||
SourceLocation PointOfInstantiation,
|
||||
ClassTemplateSpecializationDecl *ClassTemplateSpec);
|
||||
ClassTemplateSpecializationDecl *ClassTemplateSpec,
|
||||
TemplateSpecializationKind TSK);
|
||||
|
||||
NestedNameSpecifier *
|
||||
SubstNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||
|
|
|
@ -2934,7 +2934,8 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
|
||||
bool SpecializationRequiresInstantiation = true;
|
||||
if (PrevDecl) {
|
||||
if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) {
|
||||
if (PrevDecl->getSpecializationKind()
|
||||
== TSK_ExplicitInstantiationDefinition) {
|
||||
// This particular specialization has already been declared or
|
||||
// instantiated. We cannot explicitly instantiate it.
|
||||
Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate)
|
||||
|
@ -3028,16 +3029,19 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
//
|
||||
// This check comes when we actually try to perform the
|
||||
// instantiation.
|
||||
TemplateSpecializationKind TSK
|
||||
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
|
||||
: TSK_ExplicitInstantiationDeclaration;
|
||||
if (SpecializationRequiresInstantiation)
|
||||
InstantiateClassTemplateSpecialization(Specialization, true);
|
||||
InstantiateClassTemplateSpecialization(Specialization, TSK);
|
||||
else // Instantiate the members of this class template specialization.
|
||||
InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization);
|
||||
InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization,
|
||||
TSK);
|
||||
|
||||
return DeclPtrTy::make(Specialization);
|
||||
}
|
||||
|
||||
// Explicit instantiation of a member class of a class template.
|
||||
// FIXME: Implement extern template semantics.
|
||||
Sema::DeclResult
|
||||
Sema::ActOnExplicitInstantiation(Scope *S,
|
||||
SourceLocation ExternLoc,
|
||||
|
@ -3092,17 +3096,21 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
}
|
||||
}
|
||||
|
||||
TemplateSpecializationKind TSK
|
||||
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
|
||||
: TSK_ExplicitInstantiationDeclaration;
|
||||
|
||||
if (!Record->getDefinition(Context)) {
|
||||
// If the class has a definition, instantiate it (and all of its
|
||||
// members, recursively).
|
||||
Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
|
||||
if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern,
|
||||
getTemplateInstantiationArgs(Record),
|
||||
/*ExplicitInstantiation=*/true))
|
||||
TSK))
|
||||
return true;
|
||||
} else // Instantiate all of the members of the class.
|
||||
InstantiateClassMembers(TemplateLoc, Record,
|
||||
getTemplateInstantiationArgs(Record));
|
||||
getTemplateInstantiationArgs(Record), TSK);
|
||||
|
||||
// FIXME: We don't have any representation for explicit instantiations of
|
||||
// member classes. Such a representation is not needed for compilation, but it
|
||||
|
|
|
@ -623,8 +623,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
|
|||
/// \param TemplateArgs The template arguments to be substituted into
|
||||
/// the pattern.
|
||||
///
|
||||
/// \param ExplicitInstantiation whether this is an explicit instantiation
|
||||
/// (otherwise, it is an implicit instantiation).
|
||||
/// \param TSK the kind of implicit or explicit instantiation to perform.
|
||||
///
|
||||
/// \param Complain whether to complain if the class cannot be instantiated due
|
||||
/// to the lack of a definition.
|
||||
|
@ -634,7 +633,7 @@ bool
|
|||
Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
||||
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
bool ExplicitInstantiation,
|
||||
TemplateSpecializationKind TSK,
|
||||
bool Complain) {
|
||||
bool Invalid = false;
|
||||
|
||||
|
@ -650,7 +649,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
Diag(Pattern->getLocation(), diag::note_member_of_template_here);
|
||||
} else {
|
||||
Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
|
||||
<< ExplicitInstantiation
|
||||
<< (TSK != TSK_ImplicitInstantiation)
|
||||
<< Context.getTypeDeclType(Instantiation);
|
||||
Diag(Pattern->getLocation(), diag::note_template_decl_here);
|
||||
}
|
||||
|
@ -708,9 +707,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
Consumer.HandleTagDeclDefinition(Instantiation);
|
||||
|
||||
// If this is an explicit instantiation, instantiate our members, too.
|
||||
if (!Invalid && ExplicitInstantiation) {
|
||||
if (!Invalid && TSK != TSK_ImplicitInstantiation) {
|
||||
Inst.Clear();
|
||||
InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs);
|
||||
InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs,
|
||||
TSK);
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
|
@ -719,7 +719,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
|
|||
bool
|
||||
Sema::InstantiateClassTemplateSpecialization(
|
||||
ClassTemplateSpecializationDecl *ClassTemplateSpec,
|
||||
bool ExplicitInstantiation,
|
||||
TemplateSpecializationKind TSK,
|
||||
bool Complain) {
|
||||
// Perform the actual instantiation on the canonical declaration.
|
||||
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
|
||||
|
@ -798,14 +798,12 @@ Sema::InstantiateClassTemplateSpecialization(
|
|||
}
|
||||
|
||||
// Note that this is an instantiation.
|
||||
ClassTemplateSpec->setSpecializationKind(
|
||||
ExplicitInstantiation? TSK_ExplicitInstantiation
|
||||
: TSK_ImplicitInstantiation);
|
||||
ClassTemplateSpec->setSpecializationKind(TSK);
|
||||
|
||||
bool Result = InstantiateClass(ClassTemplateSpec->getLocation(),
|
||||
ClassTemplateSpec, Pattern,
|
||||
getTemplateInstantiationArgs(ClassTemplateSpec),
|
||||
ExplicitInstantiation,
|
||||
TSK,
|
||||
Complain);
|
||||
|
||||
for (unsigned I = 0, N = Matched.size(); I != N; ++I) {
|
||||
|
@ -823,7 +821,9 @@ Sema::InstantiateClassTemplateSpecialization(
|
|||
void
|
||||
Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
||||
CXXRecordDecl *Instantiation,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs) {
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
TemplateSpecializationKind TSK) {
|
||||
// FIXME: extern templates
|
||||
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
|
||||
DEnd = Instantiation->decls_end();
|
||||
D != DEnd; ++D) {
|
||||
|
@ -839,7 +839,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
|||
"Missing instantiated-from-template information");
|
||||
InstantiateClass(PointOfInstantiation, Record,
|
||||
Record->getInstantiatedFromMemberClass(),
|
||||
TemplateArgs, true);
|
||||
TemplateArgs,
|
||||
TSK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -848,9 +849,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
|
|||
/// \brief Instantiate the definitions of all of the members of the
|
||||
/// given class template specialization, which was named as part of an
|
||||
/// explicit instantiation.
|
||||
void Sema::InstantiateClassTemplateSpecializationMembers(
|
||||
void
|
||||
Sema::InstantiateClassTemplateSpecializationMembers(
|
||||
SourceLocation PointOfInstantiation,
|
||||
ClassTemplateSpecializationDecl *ClassTemplateSpec) {
|
||||
ClassTemplateSpecializationDecl *ClassTemplateSpec,
|
||||
TemplateSpecializationKind TSK) {
|
||||
// C++0x [temp.explicit]p7:
|
||||
// An explicit instantiation that names a class template
|
||||
// specialization is an explicit instantion of the same kind
|
||||
|
@ -860,7 +863,8 @@ void Sema::InstantiateClassTemplateSpecializationMembers(
|
|||
// containing the explicit instantiation, except as described
|
||||
// below.
|
||||
InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec,
|
||||
getTemplateInstantiationArgs(ClassTemplateSpec));
|
||||
getTemplateInstantiationArgs(ClassTemplateSpec),
|
||||
TSK);
|
||||
}
|
||||
|
||||
Sema::OwningStmtResult
|
||||
|
|
|
@ -402,6 +402,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
|||
|
||||
Decl *
|
||||
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
|
||||
// FIXME: Dig out the out-of-line definition of this function template?
|
||||
|
||||
TemplateParameterList *TempParams = D->getTemplateParameters();
|
||||
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
|
||||
if (!InstParams)
|
||||
|
@ -979,6 +981,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
if (!Pattern)
|
||||
return;
|
||||
|
||||
// C++0x [temp.explicit]p9:
|
||||
// Except for inline functions, other explicit instantiation declarations
|
||||
// have the effect of suppressing the implicit instantiation of the entity
|
||||
// to which they refer.
|
||||
if (Function->getTemplateSpecializationKind()
|
||||
== TSK_ExplicitInstantiationDeclaration &&
|
||||
PatternDecl->isOutOfLine() && !PatternDecl->isInline())
|
||||
return;
|
||||
|
||||
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
|
||||
if (Inst)
|
||||
return;
|
||||
|
@ -1080,6 +1091,8 @@ void Sema::InstantiateStaticDataMemberDefinition(
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: extern templates
|
||||
|
||||
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
|
||||
if (Inst)
|
||||
return;
|
||||
|
|
|
@ -1781,7 +1781,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
|
|||
if (Loc.isValid())
|
||||
ClassTemplateSpec->setLocation(Loc);
|
||||
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
|
||||
/*ExplicitInstantiation=*/false,
|
||||
TSK_ImplicitInstantiation,
|
||||
/*Complain=*/diag != 0);
|
||||
}
|
||||
} else if (CXXRecordDecl *Rec
|
||||
|
@ -1790,7 +1790,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
|
|||
// This record was instantiated from a class within a template.
|
||||
return InstantiateClass(Loc, Rec, Pattern,
|
||||
getTemplateInstantiationArgs(Rec),
|
||||
/*ExplicitInstantiation=*/false,
|
||||
TSK_ImplicitInstantiation,
|
||||
/*Complain=*/diag != 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
// RUN: clang-cc -emit-llvm -femit-all-decls -o %t %s &&
|
||||
// RUN: grep "_ZNK4plusIillEclERKiRKl" %t | count 1
|
||||
|
||||
// FIXME: We should not need the -femit-all-decls, because operator() should
|
||||
// be emitted as an external symbol rather than with linkonce_odr linkage.
|
||||
// This is a Sema problem.
|
||||
template<typename T, typename U, typename Result>
|
||||
struct plus {
|
||||
Result operator()(const T& t, const U& u) const {
|
||||
return t + u;
|
||||
}
|
||||
Result operator()(const T& t, const U& u) const;
|
||||
};
|
||||
|
||||
template<typename T, typename U, typename Result>
|
||||
Result plus<T, U, Result>::operator()(const T& t, const U& u) const {
|
||||
return t + u;
|
||||
}
|
||||
|
||||
template struct plus<int, long, long>;
|
||||
|
|
Loading…
Reference in New Issue