Skip to content

Commit

Permalink
[clang] remove ClassScopeFunctionSpecializationDecl (#66636)
Browse files Browse the repository at this point in the history
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`).
  • Loading branch information
sdkrystian authored Oct 7, 2023
1 parent 859f2d0 commit 3a3b84b
Show file tree
Hide file tree
Showing 33 changed files with 312 additions and 459 deletions.
8 changes: 3 additions & 5 deletions clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
9 changes: 0 additions & 9 deletions clang-tools-extra/clangd/SemanticHighlighting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 5 additions & 6 deletions clang/include/clang/AST/ASTNodeTraverser.h
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 4 additions & 6 deletions clang/include/clang/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
150 changes: 26 additions & 124 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand Down Expand Up @@ -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};
}
};

Expand Down Expand Up @@ -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.
///
Expand Down
17 changes: 7 additions & 10 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, {})
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/Basic/DeclNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 0 additions & 2 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 0 additions & 4 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/ASTRecordReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ class ASTRecordReader
/// Reads a TemplateArgumentLoc, advancing Idx.
TemplateArgumentLoc readTemplateArgumentLoc();

void readTemplateArgumentListInfo(TemplateArgumentListInfo &Result);

const ASTTemplateArgumentListInfo*
readASTTemplateArgumentListInfo();

Expand Down
Loading

0 comments on commit 3a3b84b

Please sign in to comment.