[clang-tools-extra] [clang] remove ClassScopeFunctionSpecializationDecl (PR #66636)
Krystian Stasiowski via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 6 13:23:48 PDT 2023
https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/66636
>From 4ea4e89cb47ed7e4d3f1cf2a9d99d2f7e9ad33bb Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Fri, 25 Aug 2023 14:07:32 -0400
Subject: [PATCH] [clang] remove ClassScopeFunctionSpecializationDecl
---
.../clang-tidy/modernize/UseEmplaceCheck.cpp | 8 +-
.../clangd/SemanticHighlighting.cpp | 9 --
clang/docs/ReleaseNotes.rst | 5 +
clang/include/clang/AST/ASTNodeTraverser.h | 11 +-
clang/include/clang/AST/Decl.h | 10 +-
clang/include/clang/AST/DeclTemplate.h | 150 +++---------------
clang/include/clang/AST/RecursiveASTVisitor.h | 17 +-
clang/include/clang/Basic/DeclNodes.td | 1 -
.../clang/Basic/DiagnosticSemaKinds.td | 8 +-
clang/include/clang/Sema/Sema.h | 6 +-
clang/include/clang/Sema/Template.h | 2 -
.../include/clang/Serialization/ASTBitCodes.h | 4 -
.../clang/Serialization/ASTRecordReader.h | 2 +
clang/lib/AST/ASTImporter.cpp | 26 ++-
clang/lib/AST/Decl.cpp | 71 ++++++---
clang/lib/AST/DeclBase.cpp | 2 -
clang/lib/AST/DeclTemplate.cpp | 13 --
clang/lib/AST/ODRHash.cpp | 4 +
clang/lib/CodeGen/CGDecl.cpp | 1 -
clang/lib/Index/IndexSymbol.cpp | 1 -
clang/lib/Sema/SemaDecl.cpp | 112 ++++++-------
clang/lib/Sema/SemaTemplate.cpp | 14 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 123 +++++++-------
clang/lib/Serialization/ASTCommon.cpp | 1 -
clang/lib/Serialization/ASTReader.cpp | 19 ++-
clang/lib/Serialization/ASTReaderDecl.cpp | 59 ++-----
clang/lib/Serialization/ASTWriter.cpp | 1 -
clang/lib/Serialization/ASTWriterDecl.cpp | 42 ++---
.../Checkers/SmartPtrModeling.cpp | 2 +-
clang/test/AST/ast-dump-decl.cpp | 9 +-
clang/test/CXX/drs/dr7xx.cpp | 5 +
.../test/SemaTemplate/instantiate-method.cpp | 23 ++-
clang/tools/libclang/CIndex.cpp | 1 -
33 files changed, 308 insertions(+), 454 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
index 554abcd900e329c..b85dde5644d313f 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
@@ -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();
}
diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp
index 45c01634e2e38d1..7649e37e1f96663 100644
--- a/clang-tools-extra/clangd/SemanticHighlighting.cpp
+++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp
@@ -715,13 +715,6 @@ class CollectExtraHighlightings
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 @@ class CollectExtraHighlightings
}
if (auto *Args = D->getTemplateSpecializationArgsAsWritten())
H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc());
- if (auto *I = D->getDependentSpecializationInfo())
- H.addAngleBracketTokens(I->getLAngleLoc(), I->getRAngleLoc());
return true;
}
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d2a435041a1542f..ea737fdb5fdad15 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -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
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 1151a756ff377b6..cc8dab97f8b010f 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -426,8 +426,12 @@ class ASTNodeTraverser
}
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 @@ class ASTNodeTraverser
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) {
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 2830861add39e7c..7f076cc77ea82cb 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2845,9 +2845,7 @@ class FunctionDecl : public DeclaratorDecl,
/// 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 @@ class FunctionDecl : public DeclaratorDecl,
/// 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;
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 6264f15d6ffb961..54d28227a4ae91b 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -583,7 +583,7 @@ class FunctionTemplateSpecializationInfo final
/// \code
/// template<typename> struct A {
/// template<typename> void f();
- /// template<> void f<int>(); // ClassScopeFunctionSpecializationDecl
+ /// template<> void f<int>();
/// };
/// \endcode
///
@@ -682,82 +682,48 @@ class MemberSpecializationInfo {
/// 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;
+ friend TrailingObjects;
- size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const {
- return NumArgs;
- }
- size_t numTrailingObjects(OverloadToken<FunctionTemplateDecl *>) const {
- return NumTemplates;
- }
+ /// The number of candidates for the primary template.
+ unsigned NumCandidates;
DependentFunctionTemplateSpecializationInfo(
- const UnresolvedSetImpl &Templates,
- const TemplateArgumentListInfo &TemplateArgs);
+ const UnresolvedSetImpl &Candidates,
+ const ASTTemplateArgumentListInfo *TemplateArgsWritten);
public:
- friend TrailingObjects;
+ /// The template arguments as written in the sources, if provided.
+ const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten;
static DependentFunctionTemplateSpecializationInfo *
- Create(ASTContext &Context, const UnresolvedSetImpl &Templates,
- const TemplateArgumentListInfo &TemplateArgs);
-
- /// Returns the number of function templates that this might
- /// be a specialization of.
- unsigned getNumTemplates() const { return NumTemplates; }
+ Create(ASTContext &Context, const UnresolvedSetImpl &Candidates,
+ const TemplateArgumentListInfo *TemplateArgs);
- /// 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 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl {
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.
///
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 298489e7d4fc413..3dd23eb38eeabfc 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -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
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index 5e726c1bdf8fa5c..8b1f415dd5fe2cb 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -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>;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3cd49bcc9ecc6a..21048b06398bfa3 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5240,11 +5240,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<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f77e109bac323eb..1c88855a73970d3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8451,9 +8451,9 @@ class Sema final {
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,
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 1de2cc6917b424a..28d603bf115950a 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -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,
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 85f49e21b2e2ec1..5c32fbc079c9a65 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -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,
diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h
index ca85163e0f21c6d..d643e54e3d923a7 100644
--- a/clang/include/clang/Serialization/ASTRecordReader.h
+++ b/clang/include/clang/Serialization/ASTRecordReader.h
@@ -155,6 +155,8 @@ class ASTRecordReader
/// Reads a TemplateArgumentLoc, advancing Idx.
TemplateArgumentLoc readTemplateArgumentLoc();
+ void readTemplateArgumentListInfo(TemplateArgumentListInfo &Result);
+
const ASTTemplateArgumentListInfo*
readASTTemplateArgumentListInfo();
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 29b9d492904f5c8..ecf13598a8d0372 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -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();
}
}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index b88df1edf845ac0..f4a73f137fcf87a 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -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;
}
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 46372f97289c30f..e2934dcc586632c 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -936,7 +936,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case BuiltinTemplate:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
- case ClassScopeFunctionSpecialization:
case VarTemplateSpecialization:
case VarTemplatePartialSpecialization:
case ObjCImplementation:
@@ -1078,7 +1077,6 @@ bool Decl::AccessDeclContextCheck() const {
// FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have
// AS_none as access specifier.
isa<CXXRecordDecl>(this) ||
- isa<ClassScopeFunctionSpecializationDecl>(this) ||
isa<LifetimeExtendedTemporaryDecl>(this))
return true;
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 5e2742b4949f260..be385ca1152546e 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -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
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 5eab315793b4113..7f9b5eb52e367eb 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -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.
}
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 99b94588f56f0a5..4d4c94d008c9dfc 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -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:
diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp
index d7316538f606141..cfdffeed834e687 100644
--- a/clang/lib/Index/IndexSymbol.cpp
+++ b/clang/lib/Index/IndexSymbol.cpp
@@ -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:
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 324a3674732aa04..c6cb04b64f545e0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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>()) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 080f005e04402cb..ff370dd1e080b2b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -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;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 071366ac0ee9834..ec0f7d1fe0ddd8e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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;
+ 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;
+ }
- Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
+ // 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,
- &ExplicitArgs,
- Previous))
+ 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;
+ 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;
+ }
- Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
+ // 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,
- &ExplicitArgs,
- Previous))
+ 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;
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 72e582107480976..6110e287b7fb50f 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -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:
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index b4d5325601e59c1..c2e080e3f593f81 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7362,15 +7362,20 @@ TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() {
return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind()));
}
-const ASTTemplateArgumentListInfo *
-ASTRecordReader::readASTTemplateArgumentListInfo() {
- SourceLocation LAngleLoc = readSourceLocation();
- SourceLocation RAngleLoc = readSourceLocation();
+void ASTRecordReader::readTemplateArgumentListInfo(
+ TemplateArgumentListInfo &Result) {
+ Result.setLAngleLoc(readSourceLocation());
+ Result.setRAngleLoc(readSourceLocation());
unsigned NumArgsAsWritten = readInt();
- TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc);
for (unsigned i = 0; i != NumArgsAsWritten; ++i)
- TemplArgsInfo.addArgument(readTemplateArgumentLoc());
- return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo);
+ Result.addArgument(readTemplateArgumentLoc());
+}
+
+const ASTTemplateArgumentListInfo *
+ASTRecordReader::readASTTemplateArgumentListInfo() {
+ TemplateArgumentListInfo Result;
+ readTemplateArgumentListInfo(Result);
+ return ASTTemplateArgumentListInfo::Create(getContext(), Result);
}
Decl *ASTReader::GetExternalDecl(uint32_t ID) {
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 6a2f607d916c472..485e18efbd02a87 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -359,8 +359,6 @@ namespace clang {
void VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
- void VisitClassScopeFunctionSpecializationDecl(
- ClassScopeFunctionSpecializationDecl *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]);
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());
-
- FD->setDependentTemplateSpecialization(Reader.getContext(),
- TemplDecls, TemplArgs);
+ TemplateArgumentListInfo TemplArgsWritten;
+ bool HasTemplateArgumentsAsWritten = Record.readBool();
+ if (HasTemplateArgumentsAsWritten)
+ Record.readTemplateArgumentListInfo(TemplArgsWritten);
+
+ 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;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 7b4ab6fe0a1f971..27700c711d52fdd 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -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);
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 91c8ed9f75db1f5..8a2ea7c7624ceb8 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -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);
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index a20d24db158f50b..66e9a501c348eb5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -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)
diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp
index 6848a2b01da2c91..017e640aeaea6d7 100644
--- a/clang/test/AST/ast-dump-decl.cpp
+++ b/clang/test/AST/ast-dump-decl.cpp
@@ -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();
diff --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp
index f6a2e5923bedb5d..11901b80d646225 100644
--- a/clang/test/CXX/drs/dr7xx.cpp
+++ b/clang/test/CXX/drs/dr7xx.cpp
@@ -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) {
diff --git a/clang/test/SemaTemplate/instantiate-method.cpp b/clang/test/SemaTemplate/instantiate-method.cpp
index 9cd668dacf5c9c5..60889a4cffe46ae 100644
--- a/clang/test/SemaTemplate/instantiate-method.cpp
+++ b/clang/test/SemaTemplate/instantiate-method.cpp
@@ -45,7 +45,7 @@ class HasDestructor {
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 }}
}
}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 7915050a78eaffc..46226f4325b0a7a 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -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:
More information about the cfe-commits
mailing list