[clang] remove ClassScopeFunctionSpecializationDecl (#66636)

This removes the `ClassScopeFunctionSpecializationDecl` `Decl` node, and
instead uses `DependentFunctionTemplateSpecializationInfo` to handle
such declarations. `DependentFunctionTemplateSpecializationInfo` is also
changed to store a `const ASTTemplateArgumentListInfo*` to be more in
line with `FunctionTemplateSpecializationInfo`.

This also changes `FunctionDecl::isFunctionTemplateSpecialization` to
return `true` for dependent specializations, and
`FunctionDecl::getTemplateSpecializationKind`/`FunctionDecl::getTemplateSpecializationKindForInstantiation`
to return `TSK_ExplicitSpecialization` for non-friend dependent
specializations (the same behavior as dependent class scope
`ClassTemplateSepcializationDecl` & `VarTemplateSepcializationDecl`).
This commit is contained in:
Krystian Stasiowski 2023-10-07 02:55:31 -04:00 committed by GitHub
parent 859f2d0323
commit 3a3b84b180
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 317 additions and 464 deletions

View File

@ -67,11 +67,9 @@ AST_MATCHER_P(CallExpr, hasLastArgument,
// function had parameters defined (this is useful to check if there is only one
// variadic argument).
AST_MATCHER(CXXMemberCallExpr, hasSameNumArgsAsDeclNumParams) {
if (Node.getMethodDecl()->isFunctionTemplateSpecialization())
return Node.getNumArgs() == Node.getMethodDecl()
->getPrimaryTemplate()
->getTemplatedDecl()
->getNumParams();
if (const FunctionTemplateDecl *Primary =
Node.getMethodDecl()->getPrimaryTemplate())
return Node.getNumArgs() == Primary->getTemplatedDecl()->getNumParams();
return Node.getNumArgs() == Node.getMethodDecl()->getNumParams();
}

View File

@ -715,13 +715,6 @@ public:
return true;
}
bool VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
if (auto *Args = D->getTemplateArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
return true;
}
bool VisitDeclRefExpr(DeclRefExpr *E) {
H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc());
return true;
@ -752,8 +745,6 @@ public:
}
if (auto *Args = D->getTemplateSpecializationArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
if (auto *I = D->getDependentSpecializationInfo())
H.addAngleBracketTokens(I->getLAngleLoc(), I->getRAngleLoc());
return true;
}

View File

@ -71,6 +71,11 @@ C++ Specific Potentially Breaking Changes
(`#49884 <https://github.com/llvm/llvm-project/issues/49884>`_), and
(`#61273 <https://github.com/llvm/llvm-project/issues/61273>`_)
- The `ClassScopeFunctionSpecializationDecl` AST node has been removed. Dependent class scope
explicit function template specializations now use `DependentFunctionTemplateSpecializationInfo`
to store candidate primary templates and explicit template arguments. This should not impact users
of Clang as a compiler, but it may break assumptions in Clang-based tools iterating over the AST.
ABI Changes in This Version
---------------------------
- Following the SystemV ABI for x86-64, ``__int128`` arguments will no longer

View File

@ -426,8 +426,12 @@ public:
}
void VisitFunctionDecl(const FunctionDecl *D) {
if (const auto *FTSI = D->getTemplateSpecializationInfo())
if (FunctionTemplateSpecializationInfo *FTSI =
D->getTemplateSpecializationInfo())
dumpTemplateArgumentList(*FTSI->TemplateArguments);
else if (DependentFunctionTemplateSpecializationInfo *DFTSI =
D->getDependentSpecializationInfo())
dumpASTTemplateArgumentListInfo(DFTSI->TemplateArgumentsAsWritten);
if (D->param_begin())
for (const auto *Parameter : D->parameters())
@ -578,11 +582,6 @@ public:
dumpTemplateParameters(D->getTemplateParameters());
}
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D) {
Visit(D->getSpecialization());
dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
}
void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); }
void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {

View File

@ -2845,9 +2845,7 @@ public:
/// Determine whether this function is a function template
/// specialization.
bool isFunctionTemplateSpecialization() const {
return getPrimaryTemplate() != nullptr;
}
bool isFunctionTemplateSpecialization() const;
/// If this function is actually a function template specialization,
/// retrieve information about this function template specialization.
@ -2930,9 +2928,9 @@ public:
/// Specifies that this function declaration is actually a
/// dependent function template specialization.
void setDependentTemplateSpecialization(ASTContext &Context,
const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo &TemplateArgs);
void setDependentTemplateSpecialization(
ASTContext &Context, const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo *TemplateArgs);
DependentFunctionTemplateSpecializationInfo *
getDependentSpecializationInfo() const;

View File

@ -583,7 +583,7 @@ public:
/// \code
/// template<typename> struct A {
/// template<typename> void f();
/// template<> void f<int>(); // ClassScopeFunctionSpecializationDecl
/// template<> void f<int>();
/// };
/// \endcode
///
@ -682,82 +682,48 @@ public:
/// Provides information about a dependent function-template
/// specialization declaration.
///
/// Since explicit function template specialization and instantiation
/// declarations can only appear in namespace scope, and you can only
/// specialize a member of a fully-specialized class, the only way to
/// get one of these is in a friend declaration like the following:
/// This is used for function templates explicit specializations declared
/// within class templates:
///
/// \code
/// template<typename> struct A {
/// template<typename> void f();
/// template<> void f<int>(); // DependentFunctionTemplateSpecializationInfo
/// };
/// \endcode
///
/// As well as dependent friend declarations naming function template
/// specializations declared within class templates:
///
/// \code
/// template \<class T> void foo(T);
/// template \<class T> class A {
/// friend void foo<>(T);
/// friend void foo<>(T); // DependentFunctionTemplateSpecializationInfo
/// };
/// \endcode
class DependentFunctionTemplateSpecializationInfo final
: private llvm::TrailingObjects<DependentFunctionTemplateSpecializationInfo,
TemplateArgumentLoc,
FunctionTemplateDecl *> {
/// The number of potential template candidates.
unsigned NumTemplates;
/// The number of template arguments.
unsigned NumArgs;
/// The locations of the left and right angle brackets.
SourceRange AngleLocs;
size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const {
return NumArgs;
}
size_t numTrailingObjects(OverloadToken<FunctionTemplateDecl *>) const {
return NumTemplates;
}
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo &TemplateArgs);
public:
friend TrailingObjects;
/// The number of candidates for the primary template.
unsigned NumCandidates;
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
const ASTTemplateArgumentListInfo *TemplateArgsWritten);
public:
/// The template arguments as written in the sources, if provided.
const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
static DependentFunctionTemplateSpecializationInfo *
Create(ASTContext &Context, const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo &TemplateArgs);
Create(ASTContext &Context, const UnresolvedSetImpl &Candidates,
const TemplateArgumentListInfo *TemplateArgs);
/// Returns the number of function templates that this might
/// be a specialization of.
unsigned getNumTemplates() const { return NumTemplates; }
/// Returns the i'th template candidate.
FunctionTemplateDecl *getTemplate(unsigned I) const {
assert(I < getNumTemplates() && "template index out of range");
return getTrailingObjects<FunctionTemplateDecl *>()[I];
}
/// Returns the explicit template arguments that were given.
const TemplateArgumentLoc *getTemplateArgs() const {
return getTrailingObjects<TemplateArgumentLoc>();
}
/// Returns the number of explicit template arguments that were given.
unsigned getNumTemplateArgs() const { return NumArgs; }
llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
return llvm::ArrayRef(getTemplateArgs(), getNumTemplateArgs());
}
/// Returns the nth template argument.
const TemplateArgumentLoc &getTemplateArg(unsigned I) const {
assert(I < getNumTemplateArgs() && "template arg index out of range");
return getTemplateArgs()[I];
}
SourceLocation getLAngleLoc() const {
return AngleLocs.getBegin();
}
SourceLocation getRAngleLoc() const {
return AngleLocs.getEnd();
/// Returns the candidates for the primary function template.
ArrayRef<FunctionTemplateDecl *> getCandidates() const {
return {getTrailingObjects<FunctionTemplateDecl *>(), NumCandidates};
}
};
@ -2613,70 +2579,6 @@ public:
static bool classofKind(Kind K) { return K == TypeAliasTemplate; }
};
/// Declaration of a function specialization at template class scope.
///
/// For example:
/// \code
/// template <class T>
/// class A {
/// template <class U> void foo(U a) { }
/// template<> void foo(int a) { }
/// }
/// \endcode
///
/// "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.
///
/// FIXME: This is redundant; we could store the same information directly on
/// the CXXMethodDecl as a DependentFunctionTemplateSpecializationInfo.
class ClassScopeFunctionSpecializationDecl : public Decl {
CXXMethodDecl *Specialization;
const ASTTemplateArgumentListInfo *TemplateArgs;
ClassScopeFunctionSpecializationDecl(
DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD,
const ASTTemplateArgumentListInfo *TemplArgs)
: Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
Specialization(FD), TemplateArgs(TemplArgs) {}
ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
: Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
virtual void anchor();
public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
CXXMethodDecl *getSpecialization() const { return Specialization; }
bool hasExplicitTemplateArgs() const { return TemplateArgs; }
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return TemplateArgs;
}
static ClassScopeFunctionSpecializationDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD,
bool HasExplicitTemplateArgs,
const TemplateArgumentListInfo &TemplateArgs) {
return new (C, DC) ClassScopeFunctionSpecializationDecl(
DC, Loc, FD,
HasExplicitTemplateArgs
? ASTTemplateArgumentListInfo::Create(C, TemplateArgs)
: nullptr);
}
static ClassScopeFunctionSpecializationDecl *
CreateDeserialized(ASTContext &Context, unsigned ID);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K == Decl::ClassScopeFunctionSpecialization;
}
};
/// Represents a variable template specialization, which refers to
/// a variable template with a given set of template arguments.
///

View File

@ -1563,16 +1563,6 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
}
})
DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
TRY_TO(TraverseDecl(D->getSpecialization()));
if (D->hasExplicitTemplateArgs()) {
TRY_TO(TraverseTemplateArgumentLocsHelper(
D->getTemplateArgsAsWritten()->getTemplateArgs(),
D->getTemplateArgsAsWritten()->NumTemplateArgs));
}
})
DEF_TRAVERSE_DECL(LinkageSpecDecl, {})
DEF_TRAVERSE_DECL(ExportDecl, {})
@ -2154,6 +2144,13 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
TALI->NumTemplateArgs));
}
}
} else if (const DependentFunctionTemplateSpecializationInfo *DFSI =
D->getDependentSpecializationInfo()) {
if (const ASTTemplateArgumentListInfo *TALI =
DFSI->TemplateArgumentsAsWritten) {
TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(),
TALI->NumTemplateArgs));
}
}
// Visit the function type itself, which can be either

View File

@ -102,7 +102,6 @@ def FriendTemplate : DeclNode<Decl>;
def StaticAssert : DeclNode<Decl>;
def Block : DeclNode<Decl, "blocks">, DeclContext;
def Captured : DeclNode<Decl>, DeclContext;
def ClassScopeFunctionSpecialization : DeclNode<Decl>;
def Import : DeclNode<Decl>;
def OMPThreadPrivate : DeclNode<Decl>;
def OMPAllocate : DeclNode<Decl>;

View File

@ -5232,11 +5232,11 @@ def err_explicit_specialization_inconsistent_storage_class : Error<
"'%select{none|extern|static|__private_extern__|auto|register}0'">;
def err_dependent_function_template_spec_no_match : Error<
"no candidate function template was found for dependent"
" friend function template specialization">;
" %select{member|friend}0 function template specialization">;
def note_dependent_function_template_spec_discard_reason : Note<
"candidate ignored: %select{not a function template"
"|not a member of the enclosing namespace;"
" did you mean to explicitly qualify the specialization?}0">;
"candidate ignored: %select{not a function template|"
"not a member of the enclosing %select{class template|"
"namespace; did you mean to explicitly qualify the specialization?}1}0">;
// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<

View File

@ -8451,9 +8451,9 @@ public:
SourceLocation PrevPtOfInstantiation,
bool &SuppressNew);
bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo &ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckDependentFunctionTemplateSpecialization(
FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
bool CheckFunctionTemplateSpecialization(
FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs,

View File

@ -630,8 +630,6 @@ enum class TemplateSubstitutionKind : char {
// A few supplemental visitor functions.
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TemplateParams,
std::optional<const ASTTemplateArgumentListInfo *>
ClassScopeSpecializationArgs = std::nullopt,
RewriteKind RK = RewriteKind::None);
Decl *VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams,

View File

@ -1475,10 +1475,6 @@ enum DeclCode {
/// template template parameter pack.
DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK,
/// A ClassScopeFunctionSpecializationDecl record a class scope
/// function specialization. (Microsoft extension).
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
/// An ImportDecl recording a module import.
DECL_IMPORT,

View File

@ -155,6 +155,8 @@ public:
/// Reads a TemplateArgumentLoc, advancing Idx.
TemplateArgumentLoc readTemplateArgumentLoc();
void readTemplateArgumentListInfo(TemplateArgumentListInfo &Result);
const ASTTemplateArgumentListInfo*
readASTTemplateArgumentListInfo();

View File

@ -3342,27 +3342,25 @@ Error ASTNodeImporter::ImportTemplateInformation(
case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
auto *FromInfo = FromFD->getDependentSpecializationInfo();
UnresolvedSet<8> TemplDecls;
unsigned NumTemplates = FromInfo->getNumTemplates();
for (unsigned I = 0; I < NumTemplates; I++) {
if (Expected<FunctionTemplateDecl *> ToFTDOrErr =
import(FromInfo->getTemplate(I)))
TemplDecls.addDecl(*ToFTDOrErr);
UnresolvedSet<8> Candidates;
for (FunctionTemplateDecl *FTD : FromInfo->getCandidates()) {
if (Expected<FunctionTemplateDecl *> ToFTDOrErr = import(FTD))
Candidates.addDecl(*ToFTDOrErr);
else
return ToFTDOrErr.takeError();
}
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(),
llvm::ArrayRef(FromInfo->getTemplateArgs(),
FromInfo->getNumTemplateArgs()),
ToTAInfo))
return Err;
const auto *FromTAArgsAsWritten = FromInfo->TemplateArgumentsAsWritten;
if (FromTAArgsAsWritten)
if (Error Err =
ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ToTAInfo))
return Err;
ToFD->setDependentTemplateSpecialization(Importer.getToContext(),
TemplDecls, ToTAInfo);
ToFD->setDependentTemplateSpecialization(
Importer.getToContext(), Candidates,
FromTAArgsAsWritten ? &ToTAInfo : nullptr);
return Error::success();
}
}

View File

@ -3975,6 +3975,12 @@ void FunctionDecl::setDescribedFunctionTemplate(
TemplateOrSpecialization = Template;
}
bool FunctionDecl::isFunctionTemplateSpecialization() const {
return TemplateOrSpecialization.is<FunctionTemplateSpecializationInfo *>() ||
TemplateOrSpecialization
.is<DependentFunctionTemplateSpecializationInfo *>();
}
void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) {
assert(TemplateOrSpecialization.isNull() &&
"Function is already a specialization");
@ -4109,6 +4115,11 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->TemplateArgumentsAsWritten;
}
if (DependentFunctionTemplateSpecializationInfo *Info =
TemplateOrSpecialization
.dyn_cast<DependentFunctionTemplateSpecializationInfo *>()) {
return Info->TemplateArgumentsAsWritten;
}
return nullptr;
}
@ -4137,10 +4148,9 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
Template->addSpecialization(Info, InsertPos);
}
void
FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context,
const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo &TemplateArgs) {
void FunctionDecl::setDependentTemplateSpecialization(
ASTContext &Context, const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo *TemplateArgs) {
assert(TemplateOrSpecialization.isNull());
DependentFunctionTemplateSpecializationInfo *Info =
DependentFunctionTemplateSpecializationInfo::Create(Context, Templates,
@ -4156,28 +4166,26 @@ FunctionDecl::getDependentSpecializationInfo() const {
DependentFunctionTemplateSpecializationInfo *
DependentFunctionTemplateSpecializationInfo::Create(
ASTContext &Context, const UnresolvedSetImpl &Ts,
const TemplateArgumentListInfo &TArgs) {
void *Buffer = Context.Allocate(
totalSizeToAlloc<TemplateArgumentLoc, FunctionTemplateDecl *>(
TArgs.size(), Ts.size()));
return new (Buffer) DependentFunctionTemplateSpecializationInfo(Ts, TArgs);
ASTContext &Context, const UnresolvedSetImpl &Candidates,
const TemplateArgumentListInfo *TArgs) {
const auto *TArgsWritten =
TArgs ? ASTTemplateArgumentListInfo::Create(Context, *TArgs) : nullptr;
return new (Context.Allocate(
totalSizeToAlloc<FunctionTemplateDecl *>(Candidates.size())))
DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten);
}
DependentFunctionTemplateSpecializationInfo::
DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts,
const TemplateArgumentListInfo &TArgs)
: AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) {
NumTemplates = Ts.size();
NumArgs = TArgs.size();
FunctionTemplateDecl **TsArray = getTrailingObjects<FunctionTemplateDecl *>();
for (unsigned I = 0, E = Ts.size(); I != E; ++I)
TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl());
TemplateArgumentLoc *ArgsArray = getTrailingObjects<TemplateArgumentLoc>();
for (unsigned I = 0, E = TArgs.size(); I != E; ++I)
new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]);
DependentFunctionTemplateSpecializationInfo(
const UnresolvedSetImpl &Candidates,
const ASTTemplateArgumentListInfo *TemplateArgsWritten)
: TemplateArgumentsAsWritten(TemplateArgsWritten),
NumCandidates(Candidates.size()) {
std::transform(Candidates.begin(), Candidates.end(),
getTrailingObjects<FunctionTemplateDecl *>(),
[](NamedDecl *ND) {
return cast<FunctionTemplateDecl>(ND->getUnderlyingDecl());
});
}
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
@ -4192,6 +4200,13 @@ TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
return MSInfo->getTemplateSpecializationKind();
// A dependent function template specialization is an explicit specialization,
// except when it's a friend declaration.
if (TemplateOrSpecialization
.is<DependentFunctionTemplateSpecializationInfo *>() &&
getFriendObjectKind() == FOK_None)
return TSK_ExplicitSpecialization;
return TSK_Undeclared;
}
@ -4206,6 +4221,11 @@ FunctionDecl::getTemplateSpecializationKindForInstantiation() const {
// template<> void f<int>() {}
// };
//
// Within the templated CXXRecordDecl, A<T>::f<int> is a dependent function
// template specialization; both getTemplateSpecializationKind() and
// getTemplateSpecializationKindForInstantiation() will return
// TSK_ExplicitSpecialization.
//
// For A<int>::f<int>():
// * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization
// * getTemplateSpecializationKindForInstantiation() will return
@ -4226,6 +4246,11 @@ FunctionDecl::getTemplateSpecializationKindForInstantiation() const {
TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>())
return MSInfo->getTemplateSpecializationKind();
if (TemplateOrSpecialization
.is<DependentFunctionTemplateSpecializationInfo *>() &&
getFriendObjectKind() == FOK_None)
return TSK_ExplicitSpecialization;
return TSK_Undeclared;
}

View File

@ -936,7 +936,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case BuiltinTemplate:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
case ClassScopeFunctionSpecialization:
case VarTemplateSpecialization:
case VarTemplatePartialSpecialization:
case ObjCImplementation:
@ -1077,9 +1076,7 @@ bool Decl::AccessDeclContextCheck() const {
isa<ParmVarDecl>(this) ||
// FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have
// AS_none as access specifier.
isa<CXXRecordDecl>(this) ||
isa<ClassScopeFunctionSpecializationDecl>(this) ||
isa<LifetimeExtendedTemporaryDecl>(this))
isa<CXXRecordDecl>(this) || isa<LifetimeExtendedTemporaryDecl>(this))
return true;
assert(Access != AS_none &&

View File

@ -1195,19 +1195,6 @@ TypeAliasTemplateDecl::newCommon(ASTContext &C) const {
return CommonPtr;
}
//===----------------------------------------------------------------------===//
// ClassScopeFunctionSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
void ClassScopeFunctionSpecializationDecl::anchor() {}
ClassScopeFunctionSpecializationDecl *
ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) ClassScopeFunctionSpecializationDecl(
nullptr, SourceLocation(), nullptr, nullptr);
}
//===----------------------------------------------------------------------===//
// VarTemplateDecl Implementation
//===----------------------------------------------------------------------===//

View File

@ -658,6 +658,10 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
if (F->isFunctionTemplateSpecialization()) {
if (!isa<CXXMethodDecl>(DC)) return;
if (DC->getLexicalParent()->isFileContext()) return;
// Skip class scope explicit function template specializations,
// as they have not yet been instantiated.
if (F->getDependentSpecializationInfo())
return;
// Inline method specializations are the only supported
// specialization for now.
}

View File

@ -96,7 +96,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::FriendTemplate:
case Decl::Block:
case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
case Decl::UsingShadow:
case Decl::ConstructorUsingShadow:
case Decl::ObjCTypeParam:

View File

@ -346,7 +346,6 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
}
break;
case Decl::ClassTemplatePartialSpecialization:
case Decl::ClassScopeFunctionSpecialization:
case Decl::ClassTemplateSpecialization:
case Decl::CXXRecord:
case Decl::Enum:

View File

@ -9775,7 +9775,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
bool isMemberSpecialization = false;
bool isFunctionTemplateSpecialization = false;
bool isDependentClassScopeExplicitSpecialization = false;
bool HasExplicitTemplateArgs = false;
TemplateArgumentListInfo TemplateArgs;
@ -10415,12 +10414,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc);
HasExplicitTemplateArgs = false;
} else {
assert((isFunctionTemplateSpecialization ||
D.getDeclSpec().isFriendSpecified()) &&
"should have a 'template<>' for this decl");
} else if (isFriend) {
// "friend void foo<>(int);" is an implicit specialization decl.
isFunctionTemplateSpecialization = true;
} else {
assert(isFunctionTemplateSpecialization &&
"should have a 'template<>' for this decl");
}
} else if (isFriend && isFunctionTemplateSpecialization) {
// This combination is only possible in a recovery case; the user
@ -10443,32 +10442,54 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().CUDA && !isFunctionTemplateSpecialization)
maybeAddCUDAHostDeviceAttrs(NewFD, Previous);
// If it's a friend (and only if it's a friend), it's possible
// that either the specialized function type or the specialized
// template is dependent, and therefore matching will fail. In
// this case, don't check the specialization yet.
if (isFunctionTemplateSpecialization && isFriend &&
(NewFD->getType()->isDependentType() || DC->isDependentContext() ||
TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
TemplateArgs.arguments()))) {
assert(HasExplicitTemplateArgs &&
"friend function specialization without template args");
if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs,
Previous))
NewFD->setInvalidDecl();
} else if (isFunctionTemplateSpecialization) {
if (CurContext->isDependentContext() && CurContext->isRecord()
&& !isFriend) {
isDependentClassScopeExplicitSpecialization = true;
} else if (!NewFD->isInvalidDecl() &&
CheckFunctionTemplateSpecialization(
NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr),
Previous))
NewFD->setInvalidDecl();
// Handle explict specializations of function templates
// and friend function declarations with an explicit
// template argument list.
if (isFunctionTemplateSpecialization) {
bool isDependentSpecialization = false;
if (isFriend) {
// For friend function specializations, this is a dependent
// specialization if its semantic context is dependent, its
// type is dependent, or if its template-id is dependent.
isDependentSpecialization =
DC->isDependentContext() || NewFD->getType()->isDependentType() ||
(HasExplicitTemplateArgs &&
TemplateSpecializationType::
anyInstantiationDependentTemplateArguments(
TemplateArgs.arguments()));
assert(!isDependentSpecialization ||
(HasExplicitTemplateArgs == isDependentSpecialization) &&
"dependent friend function specialization without template "
"args");
} else {
// For class-scope explicit specializations of function templates,
// if the lexical context is dependent, then the specialization
// is dependent.
isDependentSpecialization =
CurContext->isRecord() && CurContext->isDependentContext();
}
TemplateArgumentListInfo *ExplicitTemplateArgs =
HasExplicitTemplateArgs ? &TemplateArgs : nullptr;
if (isDependentSpecialization) {
// If it's a dependent specialization, it may not be possible
// to determine the primary template (for explicit specializations)
// or befriended declaration (for friends) until the enclosing
// template is instantiated. In such cases, we store the declarations
// found by name lookup and defer resolution until instantiation.
if (CheckDependentFunctionTemplateSpecialization(
NewFD, ExplicitTemplateArgs, Previous))
NewFD->setInvalidDecl();
} else if (!NewFD->isInvalidDecl()) {
if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs,
Previous))
NewFD->setInvalidDecl();
}
// C++ [dcl.stc]p1:
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
// FIXME: We should be checking this for dependent specializations.
FunctionTemplateSpecializationInfo *Info =
NewFD->getTemplateSpecializationInfo();
if (Info && SC != SC_None) {
@ -10491,21 +10512,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// Perform semantic checking on the function declaration.
if (!isDependentClassScopeExplicitSpecialization) {
if (!NewFD->isInvalidDecl() && NewFD->isMain())
CheckMain(NewFD, D.getDeclSpec());
if (!NewFD->isInvalidDecl() && NewFD->isMain())
CheckMain(NewFD, D.getDeclSpec());
if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
CheckMSVCRTEntryPoint(NewFD);
if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint())
CheckMSVCRTEntryPoint(NewFD);
if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isMemberSpecialization,
D.isFunctionDefinition()));
else if (!Previous.empty())
// Recover gracefully from an invalid redeclaration.
D.setRedeclaration(true);
}
if (!NewFD->isInvalidDecl())
D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous,
isMemberSpecialization,
D.isFunctionDefinition()));
else if (!Previous.empty())
// Recover gracefully from an invalid redeclaration.
D.setRedeclaration(true);
assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() ||
!D.isRedeclaration() ||
@ -10817,19 +10836,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
// Here we have an function template explicit specialization at class scope.
// The actual specialization will be postponed to template instatiation
// time via the ClassScopeFunctionSpecializationDecl node.
if (isDependentClassScopeExplicitSpecialization) {
ClassScopeFunctionSpecializationDecl *NewSpec =
ClassScopeFunctionSpecializationDecl::Create(
Context, CurContext, NewFD->getLocation(),
cast<CXXMethodDecl>(NewFD),
HasExplicitTemplateArgs, TemplateArgs);
CurContext->addDecl(NewSpec);
AddToScope = false;
}
// Diagnose availability attributes. Availability cannot be used on functions
// that are run during load/unload.
if (const auto *attr = NewFD->getAttr<AvailabilityAttr>()) {

View File

@ -9334,10 +9334,9 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
///
/// There really isn't any useful analysis we can do here, so we
/// just store the information.
bool
Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo &ExplicitTemplateArgs,
LookupResult &Previous) {
bool Sema::CheckDependentFunctionTemplateSpecialization(
FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous) {
// Remove anything from Previous that isn't a function template in
// the correct context.
DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext();
@ -9361,13 +9360,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
}
F.done();
bool IsFriend = FD->getFriendObjectKind() != Decl::FOK_None;
if (Previous.empty()) {
Diag(FD->getLocation(),
diag::err_dependent_function_template_spec_no_match);
Diag(FD->getLocation(), diag::err_dependent_function_template_spec_no_match)
<< IsFriend;
for (auto &P : DiscardedCandidates)
Diag(P.second->getLocation(),
diag::note_dependent_function_template_spec_discard_reason)
<< P.first;
<< P.first << IsFriend;
return true;
}

View File

@ -2247,42 +2247,46 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
D->isLocalExternDecl() ? Sema::ForExternalRedeclaration
: SemaRef.forRedeclarationInCurContext());
if (DependentFunctionTemplateSpecializationInfo *Info
= D->getDependentSpecializationInfo()) {
assert(isFriend && "non-friend has dependent specialization info?");
if (DependentFunctionTemplateSpecializationInfo *DFTSI =
D->getDependentSpecializationInfo()) {
assert(isFriend && "dependent specialization info on "
"non-member non-friend function?");
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
Info->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
// Map the candidate templates to their instantiations.
for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
Info->getTemplate(I),
TemplateArgs);
if (!Temp) return nullptr;
Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
TemplateArgumentListInfo ExplicitArgs;
if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) {
ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc());
ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
}
if (SemaRef.CheckFunctionTemplateSpecialization(Function,
&ExplicitArgs,
Previous))
// Map the candidates for the primary template to their instantiations.
for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) {
if (NamedDecl *ND =
SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs))
Previous.addDecl(ND);
else
return nullptr;
}
if (SemaRef.CheckFunctionTemplateSpecialization(
Function,
DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Function->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *Info =
} else if (const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateSpecializationArgsAsWritten()) {
// The name of this function was written as a template-id.
SemaRef.LookupQualifiedName(Previous, DC);
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
Info->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs,
TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(),
ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
@ -2404,8 +2408,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
CXXMethodDecl *D, TemplateParameterList *TemplateParams,
std::optional<const ASTTemplateArgumentListInfo *>
ClassScopeSpecializationArgs,
RewriteKind FunctionRewriteKind) {
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
if (FunctionTemplate && !TemplateParams) {
@ -2635,41 +2637,41 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
// If the name of this function was written as a template-id, instantiate
// the explicit template arguments.
if (DependentFunctionTemplateSpecializationInfo *Info
= D->getDependentSpecializationInfo()) {
assert(isFriend && "non-friend has dependent specialization info?");
if (DependentFunctionTemplateSpecializationInfo *DFTSI =
D->getDependentSpecializationInfo()) {
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
Info->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
// Map the candidate templates to their instantiations.
for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
Info->getTemplate(I),
TemplateArgs);
if (!Temp) return nullptr;
Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
TemplateArgumentListInfo ExplicitArgs;
if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) {
ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc());
ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
}
if (SemaRef.CheckFunctionTemplateSpecialization(Method,
&ExplicitArgs,
Previous))
// Map the candidates for the primary template to their instantiations.
for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) {
if (NamedDecl *ND =
SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs))
Previous.addDecl(ND);
else
return nullptr;
}
if (SemaRef.CheckFunctionTemplateSpecialization(
Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr,
Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (const ASTTemplateArgumentListInfo *Info =
ClassScopeSpecializationArgs.value_or(
D->getTemplateSpecializationArgsAsWritten())) {
} else if (const ASTTemplateArgumentListInfo *ArgsWritten =
D->getTemplateSpecializationArgsAsWritten()) {
SemaRef.LookupQualifiedName(Previous, DC);
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
Info->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs,
TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(),
ArgsWritten->getRAngleLoc());
if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs,
ExplicitArgs))
return nullptr;
@ -2678,14 +2680,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (ClassScopeSpecializationArgs) {
// Class-scope explicit specialization written without explicit template
// arguments.
SemaRef.LookupQualifiedName(Previous, DC);
if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous))
Method->setInvalidDecl();
IsExplicitSpecialization = true;
} else if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
@ -3510,13 +3504,6 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) {
return NewD;
}
Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *Decl) {
CXXMethodDecl *OldFD = Decl->getSpecialization();
return cast_or_null<CXXMethodDecl>(
VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten()));
}
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
SmallVector<Expr *, 5> Vars;
@ -4094,14 +4081,14 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD,
Decl *R;
if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) {
R = Instantiator.VisitCXXMethodDecl(
MD, nullptr, std::nullopt,
MD, /*TemplateParams=*/nullptr,
TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
} else {
assert(Spaceship->getFriendObjectKind() &&
"defaulted spaceship is neither a member nor a friend");
R = Instantiator.VisitFunctionDecl(
Spaceship, nullptr,
Spaceship, /*TemplateParams=*/nullptr,
TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual);
if (!R)
return nullptr;

View File

@ -424,7 +424,6 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::StaticAssert:
case Decl::Block:
case Decl::Captured:
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPAllocate:

View File

@ -7435,15 +7435,20 @@ TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() {
return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind()));
}
void ASTRecordReader::readTemplateArgumentListInfo(
TemplateArgumentListInfo &Result) {
Result.setLAngleLoc(readSourceLocation());
Result.setRAngleLoc(readSourceLocation());
unsigned NumArgsAsWritten = readInt();
for (unsigned i = 0; i != NumArgsAsWritten; ++i)
Result.addArgument(readTemplateArgumentLoc());
}
const ASTTemplateArgumentListInfo *
ASTRecordReader::readASTTemplateArgumentListInfo() {
SourceLocation LAngleLoc = readSourceLocation();
SourceLocation RAngleLoc = readSourceLocation();
unsigned NumArgsAsWritten = readInt();
TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
for (unsigned i = 0; i != NumArgsAsWritten; ++i)
TemplArgsInfo.addArgument(readTemplateArgumentLoc());
return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo);
TemplateArgumentListInfo Result;
readTemplateArgumentListInfo(Result);
return ASTTemplateArgumentListInfo::Create(getContext(), Result);
}
Decl *ASTReader::GetExternalDecl(uint32_t ID) {

View File

@ -358,9 +358,7 @@ namespace clang {
}
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
ClassTemplatePartialSpecializationDecl *D);
RedeclarableResult
VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D);
@ -950,27 +948,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
// Template args as written.
SmallVector<TemplateArgumentLoc, 8> TemplArgLocs;
SourceLocation LAngleLoc, RAngleLoc;
bool HasTemplateArgumentsAsWritten = Record.readInt();
if (HasTemplateArgumentsAsWritten) {
unsigned NumTemplateArgLocs = Record.readInt();
TemplArgLocs.reserve(NumTemplateArgLocs);
for (unsigned i = 0; i != NumTemplateArgLocs; ++i)
TemplArgLocs.push_back(Record.readTemplateArgumentLoc());
LAngleLoc = readSourceLocation();
RAngleLoc = readSourceLocation();
}
TemplateArgumentListInfo TemplArgsWritten;
bool HasTemplateArgumentsAsWritten = Record.readBool();
if (HasTemplateArgumentsAsWritten)
Record.readTemplateArgumentListInfo(TemplArgsWritten);
SourceLocation POI = readSourceLocation();
ASTContext &C = Reader.getContext();
TemplateArgumentList *TemplArgList
= TemplateArgumentList::CreateCopy(C, TemplArgs);
TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
for (unsigned i = 0, e = TemplArgLocs.size(); i != e; ++i)
TemplArgsInfo.addArgument(TemplArgLocs[i]);
TemplateArgumentList *TemplArgList =
TemplateArgumentList::CreateCopy(C, TemplArgs);
MemberSpecializationInfo *MSInfo = nullptr;
if (Record.readInt()) {
@ -985,7 +972,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FunctionTemplateSpecializationInfo *FTInfo =
FunctionTemplateSpecializationInfo::Create(
C, FD, Template, TSK, TemplArgList,
HasTemplateArgumentsAsWritten ? &TemplArgsInfo : nullptr, POI,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI,
MSInfo);
FD->TemplateOrSpecialization = FTInfo;
@ -1016,21 +1003,20 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
}
case FunctionDecl::TK_DependentFunctionTemplateSpecialization: {
// Templates.
UnresolvedSet<8> TemplDecls;
unsigned NumTemplates = Record.readInt();
while (NumTemplates--)
TemplDecls.addDecl(readDeclAs<NamedDecl>());
UnresolvedSet<8> Candidates;
unsigned NumCandidates = Record.readInt();
while (NumCandidates--)
Candidates.addDecl(readDeclAs<NamedDecl>());
// Templates args.
TemplateArgumentListInfo TemplArgs;
unsigned NumArgs = Record.readInt();
while (NumArgs--)
TemplArgs.addArgument(Record.readTemplateArgumentLoc());
TemplArgs.setLAngleLoc(readSourceLocation());
TemplArgs.setRAngleLoc(readSourceLocation());
TemplateArgumentListInfo TemplArgsWritten;
bool HasTemplateArgumentsAsWritten = Record.readBool();
if (HasTemplateArgumentsAsWritten)
Record.readTemplateArgumentListInfo(TemplArgsWritten);
FD->setDependentTemplateSpecialization(Reader.getContext(),
TemplDecls, TemplArgs);
FD->setDependentTemplateSpecialization(
Reader.getContext(), Candidates,
HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr);
// These are not merged; we don't need to merge redeclarations of dependent
// template friends.
break;
@ -2525,14 +2511,6 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
}
}
void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
VisitDecl(D);
D->Specialization = readDeclAs<CXXMethodDecl>();
if (Record.readInt())
D->TemplateArgs = Record.readASTTemplateArgumentListInfo();
}
void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D);
@ -3881,9 +3859,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION:
D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID);
break;
case DECL_FUNCTION_TEMPLATE:
D = FunctionTemplateDecl::CreateDeserialized(Context, ID);
break;

View File

@ -1029,7 +1029,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_INDIRECTFIELD);
RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK);
RECORD(DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK);
RECORD(DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION);
RECORD(DECL_IMPORT);
RECORD(DECL_OMP_THREADPRIVATE);
RECORD(DECL_EMPTY);

View File

@ -81,8 +81,6 @@ namespace clang {
void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
void VisitVarTemplatePartialSpecializationDecl(
VarTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
void VisitValueDecl(ValueDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
@ -617,15 +615,9 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// Template args as written.
Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr);
if (FTSInfo->TemplateArgumentsAsWritten) {
Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs);
for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs;
i!=e; ++i)
Record.AddTemplateArgumentLoc(
(*FTSInfo->TemplateArgumentsAsWritten)[i]);
Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc);
Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc);
}
if (FTSInfo->TemplateArgumentsAsWritten)
Record.AddASTTemplateArgumentListInfo(
FTSInfo->TemplateArgumentsAsWritten);
Record.AddSourceLocation(FTSInfo->getPointOfInstantiation());
@ -650,17 +642,16 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
DependentFunctionTemplateSpecializationInfo *
DFTSInfo = D->getDependentSpecializationInfo();
// Templates.
Record.push_back(DFTSInfo->getNumTemplates());
for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i)
Record.AddDeclRef(DFTSInfo->getTemplate(i));
// Candidates.
Record.push_back(DFTSInfo->getCandidates().size());
for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates())
Record.AddDeclRef(FTD);
// Templates args.
Record.push_back(DFTSInfo->getNumTemplateArgs());
for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i)
Record.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i));
Record.AddSourceLocation(DFTSInfo->getLAngleLoc());
Record.AddSourceLocation(DFTSInfo->getRAngleLoc());
Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr);
if (DFTSInfo->TemplateArgumentsAsWritten)
Record.AddASTTemplateArgumentListInfo(
DFTSInfo->TemplateArgumentsAsWritten);
break;
}
}
@ -1739,17 +1730,6 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
}
void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D) {
VisitDecl(D);
Record.AddDeclRef(D->getSpecialization());
Record.push_back(D->hasExplicitTemplateArgs());
if (D->hasExplicitTemplateArgs())
Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten());
Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION;
}
void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
VisitRedeclarableTemplateDecl(D);

View File

@ -202,7 +202,7 @@ static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD) {
static QualType getPointerTypeFromTemplateArg(const CallEvent &Call,
CheckerContext &C) {
const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!FD || !FD->isFunctionTemplateSpecialization())
if (!FD || !FD->getPrimaryTemplate())
return {};
const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray();
if (TemplateArgs.size() == 0)

View File

@ -645,11 +645,16 @@ class TestClassScopeFunctionSpecialization {
template<class U> void foo(U a) { }
template<> void foo<int>(int a) { }
};
// CHECK: ClassScopeFunctionSpecializationDecl
// CHECK-NEXT: CXXMethod{{.*}} foo 'void (int)'
// CHECK: FunctionTemplateDecl{{.*}} foo
// CHECK-NEXT: TemplateTypeParmDecl{{.*}} referenced class depth 1 index 0 U
// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void (U)' implicit-inline
// CHECK-NEXT: ParmVarDecl
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void (int)' explicit_specialization implicit-inline
// CHECK-NEXT: TemplateArgument{{.*}} 'int'
// CHECK-NEXT: BuiltinType{{.*}} 'int'
// CHECK-NEXT: ParmVarDecl
// CHECK-NEXT: CompoundStmt
namespace TestTemplateTypeParmDecl {
template<typename ... T, class U = int> void foo();

View File

@ -111,6 +111,11 @@ namespace dr727 { // dr727: partial
template<typename T> struct C<T*> {};
template<typename T> static const int N<T*>;
template<typename>
struct E {
template<> void f<void>() {} // expected-error {{no candidate function template}}
};
};
void d(D<int> di) {

View File

@ -45,7 +45,7 @@ public:
virtual ~HasDestructor() = 0;
};
int i = sizeof(HasDestructor<int>); // FIXME: forces instantiation, but
int i = sizeof(HasDestructor<int>); // FIXME: forces instantiation, but
// the code below should probably instantiate by itself.
int abstract_destructor[__is_abstract(HasDestructor<int>)? 1 : -1];
@ -94,7 +94,7 @@ struct X0 : X0Base {
template<typename U>
struct X1 : X0<U> {
int &f2() {
int &f2() {
return X0Base::f();
}
};
@ -129,19 +129,19 @@ namespace test1 {
}
namespace PR6947 {
template< class T >
template< class T >
struct X {
int f0( )
int f0( )
{
typedef void ( X::*impl_fun_ptr )( );
impl_fun_ptr pImpl = &X::template
f0_impl1<int>;
}
private:
private:
int f1() {
}
template< class Processor>
void f0_impl1( )
template< class Processor>
void f0_impl1( )
{
}
};
@ -154,7 +154,7 @@ namespace PR6947 {
}
namespace PR7022 {
template <typename >
template <typename >
struct X1
{
typedef int state_t( );
@ -185,13 +185,12 @@ namespace SameSignatureAfterInstantiation {
namespace PR22040 {
template <typename T> struct Foobar {
template <> void bazqux(typename T::type) {} // expected-error 2{{cannot be used prior to '::' because it has no members}}
template <> void bazqux(typename T::type) {} // expected-error {{no candidate function template was found for dependent member function template specialization}}
};
void test() {
// FIXME: we should suppress the "no member" errors
Foobar<void>::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }}
Foobar<int>::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }}
Foobar<void>::bazqux();
Foobar<int>::bazqux();
Foobar<int>::bazqux(3); // expected-error{{no member named 'bazqux' in }}
}
}

View File

@ -6848,7 +6848,6 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Captured:
case Decl::OMPCapturedExpr:
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
case Decl::CXXDeductionGuide:
case Decl::Import:
case Decl::OMPThreadPrivate: