[clang] [clang-tools-extra] Revert "[clang] Improved canonicalization for template specialization types" (PR #135354)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 11 05:15:05 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clangd
Author: Dmitry Vasilyev (slydiman)
<details>
<summary>Changes</summary>
Reverts llvm/llvm-project#<!-- -->135119 because of the assert in ASTContext.cpp, line 5619.
See #<!-- -->135352 for details.
---
Patch is 89.49 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/135354.diff
28 Files Affected:
- (modified) clang-tools-extra/clangd/AST.cpp (+1-2)
- (modified) clang/docs/ReleaseNotes.rst (-2)
- (modified) clang/include/clang/AST/ASTContext.h (+15-31)
- (modified) clang/include/clang/AST/PropertiesBase.td (+1-4)
- (modified) clang/include/clang/AST/TemplateBase.h (+2-11)
- (modified) clang/include/clang/AST/Type.h (+4-3)
- (modified) clang/include/clang/AST/TypeProperties.td (+25-5)
- (modified) clang/lib/AST/ASTContext.cpp (+107-129)
- (modified) clang/lib/AST/ASTDiagnostic.cpp (+4-4)
- (modified) clang/lib/AST/ASTImporter.cpp (+13-21)
- (modified) clang/lib/AST/DeclTemplate.cpp (+2-5)
- (modified) clang/lib/AST/QualTypeNames.cpp (+1-2)
- (modified) clang/lib/AST/TemplateBase.cpp (+4-15)
- (modified) clang/lib/AST/Type.cpp (+23-27)
- (modified) clang/lib/Sema/SemaCXXScopeSpec.cpp (+10-8)
- (modified) clang/lib/Sema/SemaExpr.cpp (+3-17)
- (modified) clang/lib/Sema/SemaLookup.cpp (+1-2)
- (modified) clang/lib/Sema/SemaTemplate.cpp (+84-78)
- (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+18-27)
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+5-6)
- (modified) clang/lib/Sema/SemaTemplateVariadic.cpp (+1-2)
- (modified) clang/lib/Sema/TreeTransform.h (+4-9)
- (modified) clang/test/CXX/class.derived/class.derived.general/p2.cpp (+1-1)
- (modified) clang/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp (+2-2)
- (modified) clang/test/SemaCXX/undefined-partial-specialization.cpp (+1-1)
- (modified) clang/test/SemaTemplate/make_integer_seq.cpp (+45-16)
- (modified) clang/test/SemaTemplate/type_pack_element.cpp (+42-15)
- (modified) clang/unittests/AST/TypePrinterTest.cpp (+3-3)
``````````diff
diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index 3b991e5e9013f..66b587f00ff4a 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -439,8 +439,7 @@ QualType declaredType(const TypeDecl *D) {
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
if (const auto *Args = CTSD->getTemplateArgsAsWritten())
return Context.getTemplateSpecializationType(
- TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
- /*CanonicalArgs=*/std::nullopt);
+ TemplateName(CTSD->getSpecializedTemplate()), Args->arguments());
return Context.getTypeDeclType(D);
}
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 69c7369755c67..db8dad268a8a7 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -301,8 +301,6 @@ Improvements to Clang's diagnostics
- Clang now better preserves the sugared types of pointers to member.
- Clang now better preserves the presence of the template keyword with dependent
prefixes.
-- Clang now in more cases avoids printing 'type-parameter-X-X' instead of the name of
- the template parameter.
- Clang now respects the current language mode when printing expressions in
diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
a bunch of HLSL types being printed as their C++ equivalents.
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index b8ea2af9215d2..b1e6344576eb5 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -367,6 +367,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
const ASTContext&>
CanonTemplateTemplateParms;
+ TemplateTemplateParmDecl *
+ getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
+
/// The typedef for the __int128_t type.
mutable TypedefDecl *Int128Decl = nullptr;
@@ -1808,26 +1811,22 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool ParameterPack,
TemplateTypeParmDecl *ParmDecl = nullptr) const;
- QualType getCanonicalTemplateSpecializationType(
- TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;
+ QualType getTemplateSpecializationType(TemplateName T,
+ ArrayRef<TemplateArgument> Args,
+ QualType Canon = QualType()) const;
QualType
- getTemplateSpecializationType(TemplateName T,
- ArrayRef<TemplateArgument> SpecifiedArgs,
- ArrayRef<TemplateArgument> CanonicalArgs,
- QualType Underlying = QualType()) const;
+ getCanonicalTemplateSpecializationType(TemplateName T,
+ ArrayRef<TemplateArgument> Args) const;
- QualType
- getTemplateSpecializationType(TemplateName T,
- ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
- ArrayRef<TemplateArgument> CanonicalArgs,
- QualType Canon = QualType()) const;
+ QualType getTemplateSpecializationType(TemplateName T,
+ ArrayRef<TemplateArgumentLoc> Args,
+ QualType Canon = QualType()) const;
- TypeSourceInfo *getTemplateSpecializationTypeInfo(
- TemplateName T, SourceLocation TLoc,
- const TemplateArgumentListInfo &SpecifiedArgs,
- ArrayRef<TemplateArgument> CanonicalArgs,
- QualType Canon = QualType()) const;
+ TypeSourceInfo *
+ getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc,
+ const TemplateArgumentListInfo &Args,
+ QualType Canon = QualType()) const;
QualType getParenType(QualType NamedType) const;
@@ -2943,21 +2942,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg)
const;
- /// Canonicalize the given template argument list.
- ///
- /// Returns true if any arguments were non-canonical, false otherwise.
- bool
- canonicalizeTemplateArguments(MutableArrayRef<TemplateArgument> Args) const;
-
- /// Canonicalize the given TemplateTemplateParmDecl.
- TemplateTemplateParmDecl *
- getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const;
-
- TemplateTemplateParmDecl *findCanonicalTemplateTemplateParmDeclInternal(
- TemplateTemplateParmDecl *TTP) const;
- TemplateTemplateParmDecl *insertCanonicalTemplateTemplateParmDeclInternal(
- TemplateTemplateParmDecl *CanonTTP) const;
-
/// Type Query functions. If the type is an instance of the specified class,
/// return the Type pointer for the underlying maximally pretty type. This
/// is a member of ASTContext because this may need to do some amount of
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 33336d57b6298..90537d47dd9c9 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -877,14 +877,11 @@ let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
def : Property<"expression", ExprRef> {
let Read = [{ node.getAsExpr() }];
}
- def : Property<"IsCanonical", Bool> {
- let Read = [{ node.isCanonicalExpr() }];
- }
def : Property<"isDefaulted", Bool> {
let Read = [{ node.getIsDefaulted() }];
}
def : Creator<[{
- return TemplateArgument(expression, IsCanonical, isDefaulted);
+ return TemplateArgument(expression, isDefaulted);
}]>;
}
let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index 279feb858e665..bea624eb04942 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -167,8 +167,6 @@ class TemplateArgument {
unsigned Kind : 31;
LLVM_PREFERRED_TYPE(bool)
unsigned IsDefaulted : 1;
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsCanonicalExpr : 1;
uintptr_t V;
};
union {
@@ -189,8 +187,7 @@ class TemplateArgument {
public:
/// Construct an empty, invalid template argument.
- constexpr TemplateArgument()
- : TypeOrValue{Null, /*IsDefaulted=*/0, /*IsCanonicalExpr=*/0, /*V=*/0} {}
+ constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
/// Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false,
@@ -265,10 +262,9 @@ class TemplateArgument {
/// This form of template argument only occurs in template argument
/// lists used for dependent types and for expression; it will not
/// occur in a non-dependent, canonical template argument list.
- TemplateArgument(Expr *E, bool IsCanonical, bool IsDefaulted = false) {
+ explicit TemplateArgument(Expr *E, bool IsDefaulted = false) {
TypeOrValue.Kind = Expression;
TypeOrValue.IsDefaulted = IsDefaulted;
- TypeOrValue.IsCanonicalExpr = IsCanonical;
TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
}
@@ -411,11 +407,6 @@ class TemplateArgument {
return reinterpret_cast<Expr *>(TypeOrValue.V);
}
- bool isCanonicalExpr() const {
- assert(getKind() == Expression && "Unexpected kind");
- return TypeOrValue.IsCanonicalExpr;
- }
-
/// Iterator that traverses the elements of a template argument pack.
using pack_iterator = const TemplateArgument *;
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index dc57170bf9160..9f6189440fabf 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -6676,9 +6676,10 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
/// replacement must, recursively, be one of these).
TemplateName Template;
- TemplateSpecializationType(TemplateName T, bool IsAlias,
+ TemplateSpecializationType(TemplateName T,
ArrayRef<TemplateArgument> Args,
- QualType Underlying);
+ QualType Canon,
+ QualType Aliased);
public:
/// Determine whether any of the given template arguments are dependent.
@@ -6746,7 +6747,7 @@ class TemplateSpecializationType : public Type, public llvm::FoldingSetNode {
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx);
static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T,
- ArrayRef<TemplateArgument> Args, QualType Underlying,
+ ArrayRef<TemplateArgument> Args,
const ASTContext &Context);
static bool classof(const Type *T) {
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 3bf9239e9cbf5..66d490850678a 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -737,19 +737,39 @@ let Class = DependentAddressSpaceType in {
}
let Class = TemplateSpecializationType in {
+ def : Property<"dependent", Bool> {
+ let Read = [{ node->isDependentType() }];
+ }
def : Property<"templateName", TemplateName> {
let Read = [{ node->getTemplateName() }];
}
- def : Property<"args", Array<TemplateArgument>> {
+ def : Property<"templateArguments", Array<TemplateArgument>> {
let Read = [{ node->template_arguments() }];
}
- def : Property<"UnderlyingType", QualType> {
- let Read = [{ node->isCanonicalUnqualified() ? QualType() :
- node->desugar() }];
+ def : Property<"underlyingType", Optional<QualType>> {
+ let Read = [{
+ node->isTypeAlias()
+ ? std::optional<QualType>(node->getAliasedType())
+ : node->isCanonicalUnqualified()
+ ? std::nullopt
+ : std::optional<QualType>(node->getCanonicalTypeInternal())
+ }];
}
def : Creator<[{
- return ctx.getTemplateSpecializationType(templateName, args, std::nullopt, UnderlyingType);
+ QualType result;
+ if (!underlyingType) {
+ result = ctx.getCanonicalTemplateSpecializationType(templateName,
+ templateArguments);
+ } else {
+ result = ctx.getTemplateSpecializationType(templateName,
+ templateArguments,
+ *underlyingType);
+ }
+ if (dependent)
+ const_cast<Type *>(result.getTypePtr())
+ ->addDependence(TypeDependence::DependentInstantiation);
+ return result;
}]>;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index b8e6245230475..00e2fa267a460 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -844,31 +844,6 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
return CanonTTP;
}
-TemplateTemplateParmDecl *
-ASTContext::findCanonicalTemplateTemplateParmDeclInternal(
- TemplateTemplateParmDecl *TTP) const {
- llvm::FoldingSetNodeID ID;
- CanonicalTemplateTemplateParm::Profile(ID, *this, TTP);
- void *InsertPos = nullptr;
- CanonicalTemplateTemplateParm *Canonical =
- CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos);
- return Canonical ? Canonical->getParam() : nullptr;
-}
-
-TemplateTemplateParmDecl *
-ASTContext::insertCanonicalTemplateTemplateParmDeclInternal(
- TemplateTemplateParmDecl *CanonTTP) const {
- llvm::FoldingSetNodeID ID;
- CanonicalTemplateTemplateParm::Profile(ID, *this, CanonTTP);
- void *InsertPos = nullptr;
- if (auto *Existing =
- CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos))
- return Existing->getParam();
- CanonTemplateTemplateParms.InsertNode(
- new (*this) CanonicalTemplateTemplateParm(CanonTTP), InsertPos);
- return CanonTTP;
-}
-
/// Check if a type can have its sanitizer instrumentation elided based on its
/// presence within an ignorelist.
bool ASTContext::isTypeIgnoredBySanitizer(const SanitizerMask &Mask,
@@ -3108,19 +3083,12 @@ static auto getCanonicalTemplateArguments(const ASTContext &C,
ArrayRef<TemplateArgument> Args,
bool &AnyNonCanonArgs) {
SmallVector<TemplateArgument, 16> CanonArgs(Args);
- AnyNonCanonArgs |= C.canonicalizeTemplateArguments(CanonArgs);
- return CanonArgs;
-}
-
-bool ASTContext::canonicalizeTemplateArguments(
- MutableArrayRef<TemplateArgument> Args) const {
- bool AnyNonCanonArgs = false;
- for (auto &Arg : Args) {
+ for (auto &Arg : CanonArgs) {
TemplateArgument OrigArg = Arg;
- Arg = getCanonicalTemplateArgument(Arg);
+ Arg = C.getCanonicalTemplateArgument(Arg);
AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
}
- return AnyNonCanonArgs;
+ return CanonArgs;
}
//===----------------------------------------------------------------------===//
@@ -5570,121 +5538,132 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
return QualType(TypeParm, 0);
}
-TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo(
- TemplateName Name, SourceLocation NameLoc,
- const TemplateArgumentListInfo &SpecifiedArgs,
- ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
- QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(),
- CanonicalArgs, Underlying);
+TypeSourceInfo *
+ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo &Args,
+ QualType Underlying) const {
+ assert(!Name.getAsDependentTemplateName() &&
+ "No dependent template names here!");
+ QualType TST =
+ getTemplateSpecializationType(Name, Args.arguments(), Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL =
DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc);
- TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc());
- TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc());
+ TL.setLAngleLoc(Args.getLAngleLoc());
+ TL.setRAngleLoc(Args.getRAngleLoc());
for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo());
+ TL.setArgLocInfo(i, Args[i].getLocInfo());
return DI;
}
-QualType ASTContext::getTemplateSpecializationType(
- TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
- ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
- SmallVector<TemplateArgument, 4> SpecifiedArgVec;
- SpecifiedArgVec.reserve(SpecifiedArgs.size());
- for (const TemplateArgumentLoc &Arg : SpecifiedArgs)
- SpecifiedArgVec.push_back(Arg.getArgument());
+QualType
+ASTContext::getTemplateSpecializationType(TemplateName Template,
+ ArrayRef<TemplateArgumentLoc> Args,
+ QualType Underlying) const {
+ assert(!Template.getAsDependentTemplateName() &&
+ "No dependent template names here!");
- return getTemplateSpecializationType(Template, SpecifiedArgVec, CanonicalArgs,
- Underlying);
+ SmallVector<TemplateArgument, 4> ArgVec;
+ ArgVec.reserve(Args.size());
+ for (const TemplateArgumentLoc &Arg : Args)
+ ArgVec.push_back(Arg.getArgument());
+
+ return getTemplateSpecializationType(Template, ArgVec, Underlying);
}
-[[maybe_unused]] static bool
-hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
+#ifndef NDEBUG
+static bool hasAnyPackExpansions(ArrayRef<TemplateArgument> Args) {
for (const TemplateArgument &Arg : Args)
if (Arg.isPackExpansion())
return true;
- return false;
-}
-QualType ASTContext::getCanonicalTemplateSpecializationType(
- TemplateName Template, ArrayRef<TemplateArgument> Args) const {
- assert(Template ==
- getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true));
- assert(!Args.empty());
-#ifndef NDEBUG
- for (const auto &Arg : Args)
- assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg)));
-#endif
-
- llvm::FoldingSetNodeID ID;
- TemplateSpecializationType::Profile(ID, Template, Args, QualType(), *this);
- void *InsertPos = nullptr;
- if (auto *T = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos))
- return QualType(T, 0);
-
- void *Mem = Allocate(sizeof(TemplateSpecializationType) +
- sizeof(TemplateArgument) * Args.size(),
- alignof(TemplateSpecializationType));
- auto *Spec = new (Mem)
- TemplateSpecializationType(Template, /*IsAlias=*/false, Args, QualType());
- assert(Spec->isDependentType() &&
- "canonical template specialization must be dependent");
- Types.push_back(Spec);
- TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
- return QualType(Spec, 0);
+ return true;
}
+#endif
-QualType ASTContext::getTemplateSpecializationType(
- TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs,
- ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
- assert(!Template.getUnderlying().getAsDependentTemplateName() &&
+QualType
+ASTContext::getTemplateSpecializationType(TemplateName Template,
+ ArrayRef<TemplateArgument> Args,
+ QualType Underlying) const {
+ assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
const auto *TD = Template.getAsTemplateDecl(/*IgnoreDeduced=*/true);
bool IsTypeAlias = TD && TD->isTypeAlias();
- if (Underlying.isNull()) {
- TemplateName CanonTemplate =
- getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
- bool NonCanonical = Template != CanonTemplate;
- SmallVector<TemplateArgument, 4> CanonArgsVec;
- if (CanonicalArgs.empty()) {
- CanonArgsVec = SmallVector<TemplateArgument, 4>(SpecifiedArgs);
- NonCanonical |= canonicalizeTemplateArguments(CanonArgsVec);
- CanonicalArgs = CanonArgsVec;
- } else {
- NonCanonical |= !llvm::equal(
- SpecifiedArgs, CanonicalArgs,
- [](const TemplateArgument &A, const TemplateArgument &B) {
- return A.structurallyEquals(B);
- });
- }
-
- // We can get here with an alias template when the specialization
- // contains a pack expansion that does not match up with a parameter
- // pack, or a builtin template which cannot be resolved due to dependency.
- assert((!isa_and_nonnull<TypeAliasTemplateDecl>(TD) ||
- hasAnyPackExpansions(CanonicalArgs)) &&
+ QualType CanonType;
+ if (!Underlying.isNull())
+ CanonType = getCanonicalType(Underlying);
+ else {
+ // We can get here with an alias template when the specialization contains
+ // a pack expansion that does not match up with a parameter pack.
+ assert((!IsTypeAlias || hasAnyPackExpansions(Args)) &&
"Caller must compute aliased type");
IsTypeAlias = false;
-
- Underlying =
- getCanonicalTemplateSpecializationType(CanonTemplate, CanonicalArgs);
- if (!NonCanonical)
- return Underlying;
+ CanonType = getCanonicalTemplateSpecializationType(Template, Args);
}
+
+ // Allocate the (non-canonical) template specialization type, but don't
+ // try to unique it: these types typically have location information that
+ // we don't unique and don't want to lose.
void *Mem = Allocate(sizeof(TemplateSpecializationType) +
- sizeof(TemplateArgument) * SpecifiedArgs.size() +
+ sizeof(TemplateArgument) * Args.size() +
(IsTypeAlias ? sizeof(QualType) : 0),
alignof(TemplateSpecializationType));
- auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias,
- SpecifiedArgs, Underly...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/135354
More information about the cfe-commits
mailing list