mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-17 08:16:47 +00:00
Reapply "[Clang][Sema] Refactor collection of multi-level template argument lists (#106585, #111173)" (#111852)
This patch reapplies #111173, fixing a bug when instantiating dependent expressions that name a member template that is later explicitly specialized for a class specialization that is implicitly instantiated. The bug is addressed by adding the `hasMemberSpecialization` function, which return `true` if _any_ redeclaration is a member specialization. This is then used when determining the instantiation pattern for a specialization of a template, and when collecting template arguments for a specialization of a template.
This commit is contained in:
parent
48bda00b28
commit
2bb3d3a3f3
@ -502,6 +502,9 @@ Bug Fixes to C++ Support
|
||||
in certain friend declarations. (#GH93099)
|
||||
- Clang now instantiates the correct lambda call operator when a lambda's class type is
|
||||
merged across modules. (#GH110401)
|
||||
- Clang now uses the correct set of template argument lists when comparing the constraints of
|
||||
out-of-line definitions and member templates explicitly specialized for a given implicit instantiation of
|
||||
a class template. (#GH102320)
|
||||
- Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
|
||||
- Fixed an assertion failure when invoking recovery call expressions with explicit attributes
|
||||
and undeclared templates. (#GH107047, #GH49093)
|
||||
|
@ -781,15 +781,11 @@ protected:
|
||||
EntryType *Entry, void *InsertPos);
|
||||
|
||||
struct CommonBase {
|
||||
CommonBase() : InstantiatedFromMember(nullptr, false) {}
|
||||
CommonBase() {}
|
||||
|
||||
/// The template from which this was most
|
||||
/// directly instantiated (or null).
|
||||
///
|
||||
/// The boolean value indicates whether this template
|
||||
/// was explicitly specialized.
|
||||
llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool>
|
||||
InstantiatedFromMember;
|
||||
RedeclarableTemplateDecl *InstantiatedFromMember = nullptr;
|
||||
|
||||
/// If non-null, points to an array of specializations (including
|
||||
/// partial specializations) known only by their external declaration IDs.
|
||||
@ -809,14 +805,19 @@ protected:
|
||||
};
|
||||
|
||||
/// Pointer to the common data shared by all declarations of this
|
||||
/// template.
|
||||
mutable CommonBase *Common = nullptr;
|
||||
/// template, and a flag indicating if the template is a member
|
||||
/// specialization.
|
||||
mutable llvm::PointerIntPair<CommonBase *, 1, bool> Common;
|
||||
|
||||
CommonBase *getCommonPtrInternal() const { return Common.getPointer(); }
|
||||
|
||||
/// Retrieves the "common" pointer shared by all (re-)declarations of
|
||||
/// the same template. Calling this routine may implicitly allocate memory
|
||||
/// for the common pointer.
|
||||
CommonBase *getCommonPtr() const;
|
||||
|
||||
void setCommonPtr(CommonBase *C) const { Common.setPointer(C); }
|
||||
|
||||
virtual CommonBase *newCommon(ASTContext &C) const = 0;
|
||||
|
||||
// Construct a template decl with name, parameters, and templated element.
|
||||
@ -857,15 +858,22 @@ public:
|
||||
/// template<> template<typename T>
|
||||
/// struct X<int>::Inner { /* ... */ };
|
||||
/// \endcode
|
||||
bool isMemberSpecialization() const {
|
||||
return getCommonPtr()->InstantiatedFromMember.getInt();
|
||||
bool isMemberSpecialization() const { return Common.getInt(); }
|
||||
|
||||
/// Determines whether any redeclaration of this template was
|
||||
/// a specialization of a member template.
|
||||
bool hasMemberSpecialization() const {
|
||||
for (const auto *D : redecls()) {
|
||||
if (D->isMemberSpecialization())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Note that this member template is a specialization.
|
||||
void setMemberSpecialization() {
|
||||
assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
|
||||
"Only member templates can be member template specializations");
|
||||
getCommonPtr()->InstantiatedFromMember.setInt(true);
|
||||
assert(!isMemberSpecialization() && "already a member specialization");
|
||||
Common.setInt(true);
|
||||
}
|
||||
|
||||
/// Retrieve the member template from which this template was
|
||||
@ -905,12 +913,12 @@ public:
|
||||
/// void X<T>::f(T, U);
|
||||
/// \endcode
|
||||
RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
|
||||
return getCommonPtr()->InstantiatedFromMember.getPointer();
|
||||
return getCommonPtr()->InstantiatedFromMember;
|
||||
}
|
||||
|
||||
void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) {
|
||||
assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
|
||||
getCommonPtr()->InstantiatedFromMember.setPointer(TD);
|
||||
assert(!getCommonPtr()->InstantiatedFromMember);
|
||||
getCommonPtr()->InstantiatedFromMember = TD;
|
||||
}
|
||||
|
||||
/// Retrieve the "injected" template arguments that correspond to the
|
||||
@ -1989,6 +1997,8 @@ public:
|
||||
/// template arguments have been deduced.
|
||||
void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec,
|
||||
const TemplateArgumentList *TemplateArgs) {
|
||||
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
|
||||
"A partial specialization cannot be instantiated from a template");
|
||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
||||
"Already set to a class template partial specialization!");
|
||||
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
|
||||
@ -2000,6 +2010,8 @@ public:
|
||||
/// Note that this class template specialization is an instantiation
|
||||
/// of the given class template.
|
||||
void setInstantiationOf(ClassTemplateDecl *TemplDecl) {
|
||||
assert(!isa<ClassTemplatePartialSpecializationDecl>(this) &&
|
||||
"A partial specialization cannot be instantiated from a template");
|
||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() &&
|
||||
"Previously set to a class template partial specialization!");
|
||||
SpecializedTemplate = TemplDecl;
|
||||
@ -2187,18 +2199,22 @@ public:
|
||||
/// struct X<int>::Inner<T*> { /* ... */ };
|
||||
/// \endcode
|
||||
bool isMemberSpecialization() const {
|
||||
const auto *First =
|
||||
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
return First->InstantiatedFromMember.getInt();
|
||||
return InstantiatedFromMember.getInt();
|
||||
}
|
||||
|
||||
/// Determines whether any redeclaration of this this class template partial
|
||||
/// specialization was a specialization of a member partial specialization.
|
||||
bool hasMemberSpecialization() const {
|
||||
for (const auto *D : redecls()) {
|
||||
if (cast<ClassTemplatePartialSpecializationDecl>(D)
|
||||
->isMemberSpecialization())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Note that this member template is a specialization.
|
||||
void setMemberSpecialization() {
|
||||
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
assert(First->InstantiatedFromMember.getPointer() &&
|
||||
"Only member templates can be member template specializations");
|
||||
return First->InstantiatedFromMember.setInt(true);
|
||||
}
|
||||
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
|
||||
|
||||
/// Retrieves the injected specialization type for this partial
|
||||
/// specialization. This is not the same as the type-decl-type for
|
||||
@ -2268,10 +2284,6 @@ protected:
|
||||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
}
|
||||
|
||||
void setCommonPtr(Common *C) {
|
||||
RedeclarableTemplateDecl::Common = C;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
friend class ASTDeclReader;
|
||||
@ -2754,6 +2766,8 @@ public:
|
||||
/// template arguments have been deduced.
|
||||
void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec,
|
||||
const TemplateArgumentList *TemplateArgs) {
|
||||
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
|
||||
"A partial specialization cannot be instantiated from a template");
|
||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
|
||||
"Already set to a variable template partial specialization!");
|
||||
auto *PS = new (getASTContext()) SpecializedPartialSpecialization();
|
||||
@ -2765,6 +2779,8 @@ public:
|
||||
/// Note that this variable template specialization is an instantiation
|
||||
/// of the given variable template.
|
||||
void setInstantiationOf(VarTemplateDecl *TemplDecl) {
|
||||
assert(!isa<VarTemplatePartialSpecializationDecl>(this) &&
|
||||
"A partial specialization cannot be instantiated from a template");
|
||||
assert(!SpecializedTemplate.is<SpecializedPartialSpecialization *>() &&
|
||||
"Previously set to a variable template partial specialization!");
|
||||
SpecializedTemplate = TemplDecl;
|
||||
@ -2949,18 +2965,23 @@ public:
|
||||
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
|
||||
/// \endcode
|
||||
bool isMemberSpecialization() const {
|
||||
const auto *First =
|
||||
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
return First->InstantiatedFromMember.getInt();
|
||||
return InstantiatedFromMember.getInt();
|
||||
}
|
||||
|
||||
/// Determines whether any redeclaration of this this variable template
|
||||
/// partial specialization was a specialization of a member partial
|
||||
/// specialization.
|
||||
bool hasMemberSpecialization() const {
|
||||
for (const auto *D : redecls()) {
|
||||
if (cast<VarTemplatePartialSpecializationDecl>(D)
|
||||
->isMemberSpecialization())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Note that this member template is a specialization.
|
||||
void setMemberSpecialization() {
|
||||
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
|
||||
assert(First->InstantiatedFromMember.getPointer() &&
|
||||
"Only member templates can be member template specializations");
|
||||
return First->InstantiatedFromMember.setInt(true);
|
||||
}
|
||||
void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
|
@ -11327,9 +11327,9 @@ public:
|
||||
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
|
||||
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
|
||||
SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
|
||||
TemplateParameterList **OuterTemplateParamLists,
|
||||
SkipBodyInfo *SkipBody = nullptr);
|
||||
SourceLocation FriendLoc,
|
||||
ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
|
||||
bool IsMemberSpecialization, SkipBodyInfo *SkipBody = nullptr);
|
||||
|
||||
/// Translates template arguments as provided by the parser
|
||||
/// into template arguments used by semantic analysis.
|
||||
@ -11368,7 +11368,8 @@ public:
|
||||
DeclResult ActOnVarTemplateSpecialization(
|
||||
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
|
||||
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
|
||||
StorageClass SC, bool IsPartialSpecialization);
|
||||
StorageClass SC, bool IsPartialSpecialization,
|
||||
bool IsMemberSpecialization);
|
||||
|
||||
/// Get the specialization of the given variable template corresponding to
|
||||
/// the specified argument list, or a null-but-valid result if the arguments
|
||||
@ -13009,28 +13010,14 @@ public:
|
||||
/// dealing with a specialization. This is only relevant for function
|
||||
/// template specializations.
|
||||
///
|
||||
/// \param Pattern If non-NULL, indicates the pattern from which we will be
|
||||
/// instantiating the definition of the given declaration, \p ND. This is
|
||||
/// used to determine the proper set of template instantiation arguments for
|
||||
/// friend function template specializations.
|
||||
///
|
||||
/// \param ForConstraintInstantiation when collecting arguments,
|
||||
/// ForConstraintInstantiation indicates we should continue looking when
|
||||
/// encountering a lambda generic call operator, and continue looking for
|
||||
/// arguments on an enclosing class template.
|
||||
///
|
||||
/// \param SkipForSpecialization when specified, any template specializations
|
||||
/// in a traversal would be ignored.
|
||||
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
|
||||
/// when encountering a specialized member function template, rather than
|
||||
/// returning immediately.
|
||||
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
|
||||
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
|
||||
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
|
||||
bool ForConstraintInstantiation = false,
|
||||
bool SkipForSpecialization = false,
|
||||
bool ForDefaultArgumentSubstitution = false);
|
||||
bool RelativeToPrimary = false, bool ForConstraintInstantiation = false);
|
||||
|
||||
/// RAII object to handle the state changes required to synthesize
|
||||
/// a function body.
|
||||
|
@ -2704,21 +2704,21 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
|
||||
if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
|
||||
auto From = VDTemplSpec->getInstantiatedFrom();
|
||||
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
|
||||
while (!VTD->isMemberSpecialization()) {
|
||||
auto *NewVTD = VTD->getInstantiatedFromMemberTemplate();
|
||||
if (!NewVTD)
|
||||
while (!VTD->hasMemberSpecialization()) {
|
||||
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
|
||||
VTD = NewVTD;
|
||||
else
|
||||
break;
|
||||
VTD = NewVTD;
|
||||
}
|
||||
return getDefinitionOrSelf(VTD->getTemplatedDecl());
|
||||
}
|
||||
if (auto *VTPSD =
|
||||
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
|
||||
while (!VTPSD->isMemberSpecialization()) {
|
||||
auto *NewVTPSD = VTPSD->getInstantiatedFromMember();
|
||||
if (!NewVTPSD)
|
||||
while (!VTPSD->hasMemberSpecialization()) {
|
||||
if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
|
||||
VTPSD = NewVTPSD;
|
||||
else
|
||||
break;
|
||||
VTPSD = NewVTPSD;
|
||||
}
|
||||
return getDefinitionOrSelf<VarDecl>(VTPSD);
|
||||
}
|
||||
@ -2727,15 +2727,14 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
|
||||
|
||||
// If this is the pattern of a variable template, find where it was
|
||||
// instantiated from. FIXME: Is this necessary?
|
||||
if (VarTemplateDecl *VarTemplate = VD->getDescribedVarTemplate()) {
|
||||
while (!VarTemplate->isMemberSpecialization()) {
|
||||
auto *NewVT = VarTemplate->getInstantiatedFromMemberTemplate();
|
||||
if (!NewVT)
|
||||
if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
|
||||
while (!VTD->hasMemberSpecialization()) {
|
||||
if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
|
||||
VTD = NewVTD;
|
||||
else
|
||||
break;
|
||||
VarTemplate = NewVT;
|
||||
}
|
||||
|
||||
return getDefinitionOrSelf(VarTemplate->getTemplatedDecl());
|
||||
return getDefinitionOrSelf(VTD->getTemplatedDecl());
|
||||
}
|
||||
|
||||
if (VD == this)
|
||||
@ -4150,11 +4149,11 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
|
||||
if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
|
||||
// If we hit a point where the user provided a specialization of this
|
||||
// template, we're done looking.
|
||||
while (!ForDefinition || !Primary->isMemberSpecialization()) {
|
||||
auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate();
|
||||
if (!NewPrimary)
|
||||
while (!ForDefinition || !Primary->hasMemberSpecialization()) {
|
||||
if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
|
||||
Primary = NewPrimary;
|
||||
else
|
||||
break;
|
||||
Primary = NewPrimary;
|
||||
}
|
||||
|
||||
return getDefinitionOrSelf(Primary->getTemplatedDecl());
|
||||
|
@ -2023,19 +2023,21 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
|
||||
if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
|
||||
auto From = TD->getInstantiatedFrom();
|
||||
if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
|
||||
while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) {
|
||||
if (NewCTD->isMemberSpecialization())
|
||||
while (!CTD->hasMemberSpecialization()) {
|
||||
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
|
||||
CTD = NewCTD;
|
||||
else
|
||||
break;
|
||||
CTD = NewCTD;
|
||||
}
|
||||
return GetDefinitionOrSelf(CTD->getTemplatedDecl());
|
||||
}
|
||||
if (auto *CTPSD =
|
||||
From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
|
||||
while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) {
|
||||
if (NewCTPSD->isMemberSpecialization())
|
||||
while (!CTPSD->hasMemberSpecialization()) {
|
||||
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
|
||||
CTPSD = NewCTPSD;
|
||||
else
|
||||
break;
|
||||
CTPSD = NewCTPSD;
|
||||
}
|
||||
return GetDefinitionOrSelf(CTPSD);
|
||||
}
|
||||
|
@ -309,16 +309,16 @@ bool TemplateDecl::isTypeAlias() const {
|
||||
void RedeclarableTemplateDecl::anchor() {}
|
||||
|
||||
RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
|
||||
if (Common)
|
||||
return Common;
|
||||
if (CommonBase *C = getCommonPtrInternal())
|
||||
return C;
|
||||
|
||||
// Walk the previous-declaration chain until we either find a declaration
|
||||
// with a common pointer or we run out of previous declarations.
|
||||
SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
|
||||
for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
|
||||
Prev = Prev->getPreviousDecl()) {
|
||||
if (Prev->Common) {
|
||||
Common = Prev->Common;
|
||||
if (CommonBase *C = Prev->getCommonPtrInternal()) {
|
||||
setCommonPtr(C);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -326,18 +326,18 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c
|
||||
}
|
||||
|
||||
// If we never found a common pointer, allocate one now.
|
||||
if (!Common) {
|
||||
if (!getCommonPtrInternal()) {
|
||||
// FIXME: If any of the declarations is from an AST file, we probably
|
||||
// need an update record to add the common data.
|
||||
|
||||
Common = newCommon(getASTContext());
|
||||
setCommonPtr(newCommon(getASTContext()));
|
||||
}
|
||||
|
||||
// Update any previous declarations we saw with the common pointer.
|
||||
for (const RedeclarableTemplateDecl *Prev : PrevDecls)
|
||||
Prev->Common = Common;
|
||||
Prev->setCommonPtr(getCommonPtrInternal());
|
||||
|
||||
return Common;
|
||||
return getCommonPtrInternal();
|
||||
}
|
||||
|
||||
void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const {
|
||||
@ -463,19 +463,17 @@ void FunctionTemplateDecl::addSpecialization(
|
||||
}
|
||||
|
||||
void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
|
||||
using Base = RedeclarableTemplateDecl;
|
||||
|
||||
// If we haven't created a common pointer yet, then it can just be created
|
||||
// with the usual method.
|
||||
if (!Base::Common)
|
||||
if (!getCommonPtrInternal())
|
||||
return;
|
||||
|
||||
Common *ThisCommon = static_cast<Common *>(Base::Common);
|
||||
Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
|
||||
Common *PrevCommon = nullptr;
|
||||
SmallVector<FunctionTemplateDecl *, 8> PreviousDecls;
|
||||
for (; Prev; Prev = Prev->getPreviousDecl()) {
|
||||
if (Prev->Base::Common) {
|
||||
PrevCommon = static_cast<Common *>(Prev->Base::Common);
|
||||
if (CommonBase *C = Prev->getCommonPtrInternal()) {
|
||||
PrevCommon = static_cast<Common *>(C);
|
||||
break;
|
||||
}
|
||||
PreviousDecls.push_back(Prev);
|
||||
@ -485,7 +483,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
|
||||
// use this common pointer.
|
||||
if (!PrevCommon) {
|
||||
for (auto *D : PreviousDecls)
|
||||
D->Base::Common = ThisCommon;
|
||||
D->setCommonPtr(ThisCommon);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -493,7 +491,7 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
|
||||
assert(ThisCommon->Specializations.size() == 0 &&
|
||||
"Can't merge incompatible declarations!");
|
||||
|
||||
Base::Common = PrevCommon;
|
||||
setCommonPtr(PrevCommon);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -585,8 +585,8 @@ static bool CheckConstraintSatisfaction(
|
||||
|
||||
ArrayRef<TemplateArgument> TemplateArgs =
|
||||
TemplateArgsLists.getNumSubstitutedLevels() > 0
|
||||
? TemplateArgsLists.getOutermost()
|
||||
: ArrayRef<TemplateArgument> {};
|
||||
? TemplateArgsLists.getInnermost()
|
||||
: ArrayRef<TemplateArgument>{};
|
||||
Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(),
|
||||
Sema::InstantiatingTemplate::ConstraintsCheck{},
|
||||
const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange);
|
||||
@ -834,7 +834,6 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
|
||||
getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
|
||||
/*Final=*/false, /*Innermost=*/std::nullopt,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
|
||||
return std::nullopt;
|
||||
@ -910,15 +909,13 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
|
||||
// Figure out the to-translation-unit depth for this function declaration for
|
||||
// the purpose of seeing if they differ by constraints. This isn't the same as
|
||||
// getTemplateDepth, because it includes already instantiated parents.
|
||||
static unsigned
|
||||
CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND,
|
||||
bool SkipForSpecialization = false) {
|
||||
static unsigned CalculateTemplateDepthForConstraints(Sema &S,
|
||||
const NamedDecl *ND) {
|
||||
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
|
||||
ND, ND->getLexicalDeclContext(), /*Final=*/false,
|
||||
/*Innermost=*/std::nullopt,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/true, SkipForSpecialization);
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
return MLTAL.getNumLevels();
|
||||
}
|
||||
|
||||
@ -957,8 +954,7 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
|
||||
DeclInfo.getDecl(), DeclInfo.getLexicalDeclContext(), /*Final=*/false,
|
||||
/*Innermost=*/std::nullopt,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true,
|
||||
/*SkipForSpecialization*/ false);
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
|
||||
if (MLTAL.getNumSubstitutedLevels() == 0)
|
||||
return ConstrExpr;
|
||||
@ -1068,16 +1064,16 @@ bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
|
||||
bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {
|
||||
assert(FD->getFriendObjectKind() && "Must be a friend!");
|
||||
|
||||
FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate();
|
||||
// The logic for non-templates is handled in ASTContext::isSameEntity, so we
|
||||
// don't have to bother checking 'DependsOnEnclosingTemplate' for a
|
||||
// non-function-template.
|
||||
assert(FD->getDescribedFunctionTemplate() &&
|
||||
"Non-function templates don't need to be checked");
|
||||
assert(FTD && "Non-function templates don't need to be checked");
|
||||
|
||||
SmallVector<const Expr *, 3> ACs;
|
||||
FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs);
|
||||
FTD->getAssociatedConstraints(ACs);
|
||||
|
||||
unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
|
||||
unsigned OldTemplateDepth = FTD->getTemplateParameters()->getDepth();
|
||||
for (const Expr *Constraint : ACs)
|
||||
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
|
||||
Constraint))
|
||||
@ -1524,7 +1520,6 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
|
||||
CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
|
||||
/*Final=*/false, CSE->getTemplateArguments(),
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
|
||||
return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL,
|
||||
@ -1805,8 +1800,8 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1,
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true);
|
||||
unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true);
|
||||
unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1);
|
||||
unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2);
|
||||
|
||||
for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) {
|
||||
if (Depth2 > Depth1) {
|
||||
|
@ -4510,10 +4510,10 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
||||
adjustDeclContextForDeclaratorDecl(New, Old);
|
||||
|
||||
// Ensure the template parameters are compatible.
|
||||
if (NewTemplate &&
|
||||
!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
|
||||
OldTemplate->getTemplateParameters(),
|
||||
/*Complain=*/true, TPL_TemplateMatch))
|
||||
if (NewTemplate && !TemplateParameterListsAreEqual(
|
||||
NewTemplate, NewTemplate->getTemplateParameters(),
|
||||
OldTemplate, OldTemplate->getTemplateParameters(),
|
||||
/*Complain=*/true, TPL_TemplateMatch))
|
||||
return New->setInvalidDecl();
|
||||
|
||||
// C++ [class.mem]p1:
|
||||
@ -7663,7 +7663,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
||||
: SourceLocation();
|
||||
DeclResult Res = ActOnVarTemplateSpecialization(
|
||||
S, D, TInfo, Previous, TemplateKWLoc, TemplateParams, SC,
|
||||
IsPartialSpecialization);
|
||||
IsPartialSpecialization, IsMemberSpecialization);
|
||||
if (Res.isInvalid())
|
||||
return nullptr;
|
||||
NewVD = cast<VarDecl>(Res.get());
|
||||
@ -7682,6 +7682,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
||||
VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name,
|
||||
TemplateParams, NewVD);
|
||||
NewVD->setDescribedVarTemplate(NewTemplate);
|
||||
// If we are providing an explicit specialization of a static variable
|
||||
// template, make a note of that.
|
||||
if (IsMemberSpecialization)
|
||||
NewTemplate->setMemberSpecialization();
|
||||
}
|
||||
|
||||
// If this decl has an auto type in need of deduction, make a note of the
|
||||
@ -8059,12 +8063,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
|
||||
? TPC_ClassTemplateMember
|
||||
: TPC_VarTemplate))
|
||||
NewVD->setInvalidDecl();
|
||||
|
||||
// If we are providing an explicit specialization of a static variable
|
||||
// template, make a note of that.
|
||||
if (PrevVarTemplate &&
|
||||
PrevVarTemplate->getInstantiatedFromMemberTemplate())
|
||||
PrevVarTemplate->setMemberSpecialization();
|
||||
}
|
||||
}
|
||||
|
||||
@ -9871,6 +9869,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||
NewFD);
|
||||
FunctionTemplate->setLexicalDeclContext(CurContext);
|
||||
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
|
||||
if (isMemberSpecialization)
|
||||
FunctionTemplate->setMemberSpecialization();
|
||||
|
||||
// For source fidelity, store the other template param lists.
|
||||
if (TemplateParamLists.size() > 1) {
|
||||
@ -12028,10 +12028,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
||||
|
||||
// If this is an explicit specialization of a member that is a function
|
||||
// template, mark it as a member specialization.
|
||||
if (IsMemberSpecialization &&
|
||||
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
|
||||
NewTemplateDecl->setMemberSpecialization();
|
||||
assert(OldTemplateDecl->isMemberSpecialization());
|
||||
if (IsMemberSpecialization) {
|
||||
// Explicit specializations of a member template do not inherit deleted
|
||||
// status from the parent member template that they are specializing.
|
||||
if (OldFD->isDeleted()) {
|
||||
@ -17093,8 +17090,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
|
||||
DeclResult Result = CheckClassTemplate(
|
||||
S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attrs, TemplateParams,
|
||||
AS, ModulePrivateLoc,
|
||||
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.size() - 1,
|
||||
TemplateParameterLists.data(), SkipBody);
|
||||
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
|
||||
isMemberSpecialization, SkipBody);
|
||||
return Result.get();
|
||||
} else {
|
||||
// The "template<>" header is extraneous.
|
||||
|
@ -17416,8 +17416,8 @@ DeclResult Sema::ActOnTemplatedFriendTag(
|
||||
return CheckClassTemplate(S, TagSpec, TagUseKind::Friend, TagLoc, SS,
|
||||
Name, NameLoc, Attr, TemplateParams, AS_public,
|
||||
/*ModulePrivateLoc=*/SourceLocation(),
|
||||
FriendLoc, TempParamLists.size() - 1,
|
||||
TempParamLists.data())
|
||||
FriendLoc, TempParamLists.drop_back(),
|
||||
IsMemberSpecialization)
|
||||
.get();
|
||||
} else {
|
||||
// The "template<>" header is extraneous.
|
||||
|
@ -9953,7 +9953,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
|
||||
auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
|
||||
auto *Pattern = Template;
|
||||
while (Pattern->getInstantiatedFromMemberTemplate()) {
|
||||
if (Pattern->isMemberSpecialization())
|
||||
if (Pattern->hasMemberSpecialization())
|
||||
break;
|
||||
Pattern = Pattern->getInstantiatedFromMemberTemplate();
|
||||
}
|
||||
|
@ -1795,8 +1795,9 @@ DeclResult Sema::CheckClassTemplate(
|
||||
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
|
||||
const ParsedAttributesView &Attr, TemplateParameterList *TemplateParams,
|
||||
AccessSpecifier AS, SourceLocation ModulePrivateLoc,
|
||||
SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists,
|
||||
TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody) {
|
||||
SourceLocation FriendLoc,
|
||||
ArrayRef<TemplateParameterList *> OuterTemplateParamLists,
|
||||
bool IsMemberSpecialization, SkipBodyInfo *SkipBody) {
|
||||
assert(TemplateParams && TemplateParams->size() > 0 &&
|
||||
"No template parameters");
|
||||
assert(TUK != TagUseKind::Reference &&
|
||||
@ -1984,19 +1985,6 @@ DeclResult Sema::CheckClassTemplate(
|
||||
}
|
||||
|
||||
if (PrevClassTemplate) {
|
||||
// Ensure that the template parameter lists are compatible. Skip this check
|
||||
// for a friend in a dependent context: the template parameter list itself
|
||||
// could be dependent.
|
||||
if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
|
||||
!TemplateParameterListsAreEqual(
|
||||
TemplateCompareNewDeclInfo(SemanticContext ? SemanticContext
|
||||
: CurContext,
|
||||
CurContext, KWLoc),
|
||||
TemplateParams, PrevClassTemplate,
|
||||
PrevClassTemplate->getTemplateParameters(), /*Complain=*/true,
|
||||
TPL_TemplateMatch))
|
||||
return true;
|
||||
|
||||
// C++ [temp.class]p4:
|
||||
// In a redeclaration, partial specialization, explicit
|
||||
// specialization or explicit instantiation of a class template,
|
||||
@ -2011,30 +1999,6 @@ DeclResult Sema::CheckClassTemplate(
|
||||
Diag(PrevRecordDecl->getLocation(), diag::note_previous_use);
|
||||
Kind = PrevRecordDecl->getTagKind();
|
||||
}
|
||||
|
||||
// Check for redefinition of this class template.
|
||||
if (TUK == TagUseKind::Definition) {
|
||||
if (TagDecl *Def = PrevRecordDecl->getDefinition()) {
|
||||
// If we have a prior definition that is not visible, treat this as
|
||||
// simply making that previous definition visible.
|
||||
NamedDecl *Hidden = nullptr;
|
||||
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
|
||||
SkipBody->ShouldSkip = true;
|
||||
SkipBody->Previous = Def;
|
||||
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
|
||||
assert(Tmpl && "original definition of a class template is not a "
|
||||
"class template?");
|
||||
makeMergedDefinitionVisible(Hidden);
|
||||
makeMergedDefinitionVisible(Tmpl);
|
||||
} else {
|
||||
Diag(NameLoc, diag::err_redefinition) << Name;
|
||||
Diag(Def->getLocation(), diag::note_previous_definition);
|
||||
// FIXME: Would it make sense to try to "forget" the previous
|
||||
// definition, as part of error recovery?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (PrevDecl) {
|
||||
// C++ [temp]p5:
|
||||
// A class template shall not have the same name as any other
|
||||
@ -2046,23 +2010,6 @@ DeclResult Sema::CheckClassTemplate(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check the template parameter list of this declaration, possibly
|
||||
// merging in the template parameter list from the previous class
|
||||
// template declaration. Skip this check for a friend in a dependent
|
||||
// context, because the template parameter list might be dependent.
|
||||
if (!(TUK == TagUseKind::Friend && CurContext->isDependentContext()) &&
|
||||
CheckTemplateParameterList(
|
||||
TemplateParams,
|
||||
PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate)
|
||||
: nullptr,
|
||||
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
|
||||
SemanticContext->isDependentContext())
|
||||
? TPC_ClassTemplateMember
|
||||
: TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
|
||||
: TPC_ClassTemplate,
|
||||
SkipBody))
|
||||
Invalid = true;
|
||||
|
||||
if (SS.isSet()) {
|
||||
// If the name of the template was qualified, we must be defining the
|
||||
// template out-of-line.
|
||||
@ -2089,10 +2036,8 @@ DeclResult Sema::CheckClassTemplate(
|
||||
PrevClassTemplate->getTemplatedDecl() : nullptr,
|
||||
/*DelayTypeCreation=*/true);
|
||||
SetNestedNameSpecifier(*this, NewClass, SS);
|
||||
if (NumOuterTemplateParamLists > 0)
|
||||
NewClass->setTemplateParameterListsInfo(
|
||||
Context,
|
||||
llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists));
|
||||
if (!OuterTemplateParamLists.empty())
|
||||
NewClass->setTemplateParameterListsInfo(Context, OuterTemplateParamLists);
|
||||
|
||||
// Add alignment attributes if necessary; these attributes are checked when
|
||||
// the ASTContext lays out the structure.
|
||||
@ -2105,7 +2050,10 @@ DeclResult Sema::CheckClassTemplate(
|
||||
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
|
||||
DeclarationName(Name), TemplateParams,
|
||||
NewClass);
|
||||
|
||||
// If we are providing an explicit specialization of a member that is a
|
||||
// class template, make a note of that.
|
||||
if (IsMemberSpecialization)
|
||||
NewTemplate->setMemberSpecialization();
|
||||
if (ShouldAddRedecl)
|
||||
NewTemplate->setPreviousDecl(PrevClassTemplate);
|
||||
|
||||
@ -2120,12 +2068,6 @@ DeclResult Sema::CheckClassTemplate(
|
||||
assert(T->isDependentType() && "Class template type is not dependent?");
|
||||
(void)T;
|
||||
|
||||
// If we are providing an explicit specialization of a member that is a
|
||||
// class template, make a note of that.
|
||||
if (PrevClassTemplate &&
|
||||
PrevClassTemplate->getInstantiatedFromMemberTemplate())
|
||||
PrevClassTemplate->setMemberSpecialization();
|
||||
|
||||
// Set the access specifier.
|
||||
if (!Invalid && TUK != TagUseKind::Friend &&
|
||||
NewTemplate->getDeclContext()->isRecord())
|
||||
@ -2135,8 +2077,62 @@ DeclResult Sema::CheckClassTemplate(
|
||||
NewClass->setLexicalDeclContext(CurContext);
|
||||
NewTemplate->setLexicalDeclContext(CurContext);
|
||||
|
||||
if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip))
|
||||
NewClass->startDefinition();
|
||||
// Ensure that the template parameter lists are compatible. Skip this check
|
||||
// for a friend in a dependent context: the template parameter list itself
|
||||
// could be dependent.
|
||||
if (ShouldAddRedecl && PrevClassTemplate &&
|
||||
!TemplateParameterListsAreEqual(
|
||||
NewTemplate, TemplateParams, PrevClassTemplate,
|
||||
PrevClassTemplate->getTemplateParameters(),
|
||||
/*Complain=*/true, TPL_TemplateMatch))
|
||||
return true;
|
||||
|
||||
// Check the template parameter list of this declaration, possibly
|
||||
// merging in the template parameter list from the previous class
|
||||
// template declaration. Skip this check for a friend in a dependent
|
||||
// context, because the template parameter list might be dependent.
|
||||
if (ShouldAddRedecl &&
|
||||
CheckTemplateParameterList(
|
||||
TemplateParams,
|
||||
PrevClassTemplate ? PrevClassTemplate->getTemplateParameters()
|
||||
: nullptr,
|
||||
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
|
||||
SemanticContext->isDependentContext())
|
||||
? TPC_ClassTemplateMember
|
||||
: TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
|
||||
: TPC_ClassTemplate,
|
||||
SkipBody))
|
||||
Invalid = true;
|
||||
|
||||
if (TUK == TagUseKind::Definition) {
|
||||
if (PrevClassTemplate) {
|
||||
// Check for redefinition of this class template.
|
||||
if (TagDecl *Def =
|
||||
PrevClassTemplate->getTemplatedDecl()->getDefinition()) {
|
||||
// If we have a prior definition that is not visible, treat this as
|
||||
// simply making that previous definition visible.
|
||||
NamedDecl *Hidden = nullptr;
|
||||
if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) {
|
||||
SkipBody->ShouldSkip = true;
|
||||
SkipBody->Previous = Def;
|
||||
auto *Tmpl = cast<CXXRecordDecl>(Hidden)->getDescribedClassTemplate();
|
||||
assert(Tmpl && "original definition of a class template is not a "
|
||||
"class template?");
|
||||
makeMergedDefinitionVisible(Hidden);
|
||||
makeMergedDefinitionVisible(Tmpl);
|
||||
} else {
|
||||
Diag(NameLoc, diag::err_redefinition) << Name;
|
||||
Diag(Def->getLocation(), diag::note_previous_definition);
|
||||
// FIXME: Would it make sense to try to "forget" the previous
|
||||
// definition, as part of error recovery?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SkipBody || !SkipBody->ShouldSkip)
|
||||
NewClass->startDefinition();
|
||||
}
|
||||
|
||||
ProcessDeclAttributeList(S, NewClass, Attr);
|
||||
ProcessAPINotes(NewClass);
|
||||
@ -4133,7 +4129,8 @@ void Sema::CheckDeductionGuideTemplate(FunctionTemplateDecl *TD) {
|
||||
DeclResult Sema::ActOnVarTemplateSpecialization(
|
||||
Scope *S, Declarator &D, TypeSourceInfo *DI, LookupResult &Previous,
|
||||
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
|
||||
StorageClass SC, bool IsPartialSpecialization) {
|
||||
StorageClass SC, bool IsPartialSpecialization,
|
||||
bool IsMemberSpecialization) {
|
||||
// D must be variable template id.
|
||||
assert(D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId &&
|
||||
"Variable template specialization is declared with a template id.");
|
||||
@ -4251,17 +4248,16 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
|
||||
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
|
||||
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
|
||||
CanonicalConverted);
|
||||
// If we are providing an explicit specialization of a member variable
|
||||
// template specialization, make a note of that.
|
||||
if (IsMemberSpecialization)
|
||||
Partial->setMemberSpecialization();
|
||||
Partial->setTemplateArgsAsWritten(TemplateArgs);
|
||||
|
||||
if (!PrevPartial)
|
||||
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
|
||||
Specialization = Partial;
|
||||
|
||||
// If we are providing an explicit specialization of a member variable
|
||||
// template specialization, make a note of that.
|
||||
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
|
||||
PrevPartial->setMemberSpecialization();
|
||||
|
||||
CheckTemplatePartialSpecialization(Partial);
|
||||
} else {
|
||||
// Create a new class template specialization declaration node for
|
||||
@ -5776,9 +5772,7 @@ bool Sema::CheckTemplateArgumentList(
|
||||
|
||||
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
|
||||
Template, NewContext, /*Final=*/false, CanonicalConverted,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConceptInstantiation=*/true);
|
||||
/*RelativeToPrimary=*/true, /*ForConceptInstantiation=*/true);
|
||||
if (EnsureTemplateArgumentListConstraints(
|
||||
Template, MLTAL,
|
||||
SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) {
|
||||
@ -8467,15 +8461,12 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
|
||||
<< /*class template*/ 0 << (TUK == TagUseKind::Definition)
|
||||
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
|
||||
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
|
||||
ClassTemplate->getIdentifier(),
|
||||
TemplateNameLoc,
|
||||
Attr,
|
||||
TemplateParams,
|
||||
AS_none, /*ModulePrivateLoc=*/SourceLocation(),
|
||||
/*FriendLoc*/SourceLocation(),
|
||||
TemplateParameterLists.size() - 1,
|
||||
TemplateParameterLists.data());
|
||||
return CheckClassTemplate(
|
||||
S, TagSpec, TUK, KWLoc, SS, ClassTemplate->getIdentifier(),
|
||||
TemplateNameLoc, Attr, TemplateParams, AS_none,
|
||||
/*ModulePrivateLoc=*/SourceLocation(),
|
||||
/*FriendLoc*/ SourceLocation(), TemplateParameterLists.drop_back(),
|
||||
isMemberSpecialization);
|
||||
}
|
||||
|
||||
// Create a new class template partial specialization declaration node.
|
||||
@ -8485,6 +8476,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
ClassTemplatePartialSpecializationDecl::Create(
|
||||
Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams,
|
||||
ClassTemplate, CanonicalConverted, CanonType, PrevPartial);
|
||||
|
||||
// If we are providing an explicit specialization of a member class
|
||||
// template specialization, make a note of that.
|
||||
if (isMemberSpecialization)
|
||||
Partial->setMemberSpecialization();
|
||||
Partial->setTemplateArgsAsWritten(TemplateArgs);
|
||||
SetNestedNameSpecifier(*this, Partial, SS);
|
||||
if (TemplateParameterLists.size() > 1 && SS.isSet()) {
|
||||
@ -8496,11 +8492,6 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
|
||||
ClassTemplate->AddPartialSpecialization(Partial, InsertPos);
|
||||
Specialization = Partial;
|
||||
|
||||
// If we are providing an explicit specialization of a member class
|
||||
// template specialization, make a note of that.
|
||||
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
|
||||
PrevPartial->setMemberSpecialization();
|
||||
|
||||
CheckTemplatePartialSpecialization(Partial);
|
||||
} else {
|
||||
// Create a new class template specialization declaration node for
|
||||
@ -9100,8 +9091,8 @@ bool Sema::CheckFunctionTemplateSpecialization(
|
||||
TemplateDeductionInfo Info(FailedCandidates.getLocation());
|
||||
FunctionDecl *Specialization = nullptr;
|
||||
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
|
||||
cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()),
|
||||
ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info);
|
||||
FunTmpl, ExplicitTemplateArgs ? &Args : nullptr, FT,
|
||||
Specialization, Info);
|
||||
TDK != TemplateDeductionResult::Success) {
|
||||
// Template argument deduction failed; record why it failed, so
|
||||
// that we can provide nifty diagnostics.
|
||||
@ -11299,8 +11290,8 @@ private:
|
||||
|
||||
template<typename TemplDecl>
|
||||
void checkTemplate(TemplDecl *TD) {
|
||||
if (TD->isMemberSpecialization()) {
|
||||
if (!CheckMemberSpecialization(TD))
|
||||
if (TD->getMostRecentDecl()->isMemberSpecialization()) {
|
||||
if (!CheckMemberSpecialization(TD->getMostRecentDecl()))
|
||||
diagnose(TD->getMostRecentDecl(), false);
|
||||
}
|
||||
}
|
||||
|
@ -3138,20 +3138,6 @@ template<>
|
||||
struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
template <typename TemplateDeclT>
|
||||
static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) {
|
||||
return false;
|
||||
}
|
||||
template <>
|
||||
bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>(
|
||||
VarTemplatePartialSpecializationDecl *Spec) {
|
||||
return !Spec->isClassScopeExplicitSpecialization();
|
||||
}
|
||||
template <>
|
||||
bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>(
|
||||
ClassTemplatePartialSpecializationDecl *Spec) {
|
||||
return !Spec->isClassScopeExplicitSpecialization();
|
||||
}
|
||||
|
||||
template <typename TemplateDeclT>
|
||||
static TemplateDeductionResult
|
||||
@ -3162,23 +3148,10 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
|
||||
llvm::SmallVector<const Expr *, 3> AssociatedConstraints;
|
||||
Template->getAssociatedConstraints(AssociatedConstraints);
|
||||
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost;
|
||||
// If we don't need to replace the deduced template arguments,
|
||||
// we can add them immediately as the inner-most argument list.
|
||||
if (!DeducedArgsNeedReplacement(Template))
|
||||
Innermost = CanonicalDeducedArgs;
|
||||
|
||||
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
|
||||
Template, Template->getDeclContext(), /*Final=*/false, Innermost,
|
||||
/*RelativeToPrimary=*/true, /*Pattern=*/
|
||||
nullptr, /*ForConstraintInstantiation=*/true);
|
||||
|
||||
// getTemplateInstantiationArgs picks up the non-deduced version of the
|
||||
// template args when this is a variable template partial specialization and
|
||||
// not class-scope explicit specialization, so replace with Deduced Args
|
||||
// instead of adding to inner-most.
|
||||
if (!Innermost)
|
||||
MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
|
||||
Template, Template->getDeclContext(), /*Final=*/false,
|
||||
/*Innermost=*/CanonicalDeducedArgs, /*RelativeToPrimary=*/true,
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
|
||||
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
|
||||
Info.getLocation(),
|
||||
|
@ -765,7 +765,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
|
||||
}
|
||||
// Template arguments used to transform the template arguments in
|
||||
// DeducedResults.
|
||||
SmallVector<TemplateArgument> TemplateArgsForBuildingRC(
|
||||
SmallVector<TemplateArgument> InnerArgsForBuildingRC(
|
||||
F->getTemplateParameters()->size());
|
||||
// Transform the transformed template args
|
||||
MultiLevelTemplateArgumentList Args;
|
||||
@ -778,33 +778,30 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
|
||||
NamedDecl *TP = F->getTemplateParameters()->getParam(Index);
|
||||
MultiLevelTemplateArgumentList Args;
|
||||
Args.setKind(TemplateSubstitutionKind::Rewrite);
|
||||
Args.addOuterTemplateArguments(TemplateArgsForBuildingRC);
|
||||
Args.addOuterTemplateArguments(InnerArgsForBuildingRC);
|
||||
// Rebuild the template parameter with updated depth and index.
|
||||
NamedDecl *NewParam =
|
||||
transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args,
|
||||
/*NewIndex=*/FirstUndeducedParamIdx,
|
||||
getDepthAndIndex(TP).first + AdjustDepth);
|
||||
FirstUndeducedParamIdx += 1;
|
||||
assert(TemplateArgsForBuildingRC[Index].isNull());
|
||||
TemplateArgsForBuildingRC[Index] =
|
||||
Context.getInjectedTemplateArg(NewParam);
|
||||
assert(InnerArgsForBuildingRC[Index].isNull());
|
||||
InnerArgsForBuildingRC[Index] = Context.getInjectedTemplateArg(NewParam);
|
||||
continue;
|
||||
}
|
||||
TemplateArgumentLoc Input =
|
||||
SemaRef.getTrivialTemplateArgumentLoc(D, QualType(), SourceLocation{});
|
||||
TemplateArgumentLoc Output;
|
||||
if (!SemaRef.SubstTemplateArgument(Input, Args, Output)) {
|
||||
assert(TemplateArgsForBuildingRC[Index].isNull() &&
|
||||
assert(InnerArgsForBuildingRC[Index].isNull() &&
|
||||
"InstantiatedArgs must be null before setting");
|
||||
TemplateArgsForBuildingRC[Index] = Output.getArgument();
|
||||
InnerArgsForBuildingRC[Index] = Output.getArgument();
|
||||
}
|
||||
}
|
||||
|
||||
// A list of template arguments for transforming the require-clause of F.
|
||||
// It must contain the entire set of template argument lists.
|
||||
MultiLevelTemplateArgumentList ArgsForBuildingRC;
|
||||
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
|
||||
ArgsForBuildingRC.addOuterTemplateArguments(TemplateArgsForBuildingRC);
|
||||
// A list of template arguments for transforming the require-clause using
|
||||
// the transformed template arguments as the template argument list of F.
|
||||
//
|
||||
// For 2), if the underlying deduction guide F is nested in a class template,
|
||||
// we need the entire template argument list, as the constraint AST in the
|
||||
// require-clause of F remains completely uninstantiated.
|
||||
@ -827,25 +824,15 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F,
|
||||
// - The occurrence of U in the function parameter is [depth:0, index:0]
|
||||
// - The template parameter of U is [depth:0, index:0]
|
||||
//
|
||||
// We add the outer template arguments which is [int] to the multi-level arg
|
||||
// list to ensure that the occurrence U in `C<U>` will be replaced with int
|
||||
// during the substitution.
|
||||
//
|
||||
// NOTE: The underlying deduction guide F is instantiated -- either from an
|
||||
// explicitly-written deduction guide member, or from a constructor.
|
||||
// getInstantiatedFromMemberTemplate() can only handle the former case, so we
|
||||
// check the DeclContext kind.
|
||||
if (F->getLexicalDeclContext()->getDeclKind() ==
|
||||
clang::Decl::ClassTemplateSpecialization) {
|
||||
auto OuterLevelArgs = SemaRef.getTemplateInstantiationArgs(
|
||||
F, F->getLexicalDeclContext(),
|
||||
/*Final=*/false, /*Innermost=*/std::nullopt,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
for (auto It : OuterLevelArgs)
|
||||
ArgsForBuildingRC.addOuterTemplateArguments(It.Args);
|
||||
}
|
||||
MultiLevelTemplateArgumentList ArgsForBuildingRC =
|
||||
SemaRef.getTemplateInstantiationArgs(F, F->getLexicalDeclContext(),
|
||||
/*Final=*/false,
|
||||
/*Innermost=*/InnerArgsForBuildingRC,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
ArgsForBuildingRC.setKind(clang::TemplateSubstitutionKind::Rewrite);
|
||||
|
||||
ExprResult E = SemaRef.SubstExpr(RC, ArgsForBuildingRC);
|
||||
if (E.isInvalid())
|
||||
|
@ -52,38 +52,6 @@ using namespace sema;
|
||||
//===----------------------------------------------------------------------===/
|
||||
|
||||
namespace {
|
||||
namespace TemplateInstArgsHelpers {
|
||||
struct Response {
|
||||
const Decl *NextDecl = nullptr;
|
||||
bool IsDone = false;
|
||||
bool ClearRelativeToPrimary = true;
|
||||
static Response Done() {
|
||||
Response R;
|
||||
R.IsDone = true;
|
||||
return R;
|
||||
}
|
||||
static Response ChangeDecl(const Decl *ND) {
|
||||
Response R;
|
||||
R.NextDecl = ND;
|
||||
return R;
|
||||
}
|
||||
static Response ChangeDecl(const DeclContext *Ctx) {
|
||||
Response R;
|
||||
R.NextDecl = Decl::castFromDeclContext(Ctx);
|
||||
return R;
|
||||
}
|
||||
|
||||
static Response UseNextDecl(const Decl *CurDecl) {
|
||||
return ChangeDecl(CurDecl->getDeclContext());
|
||||
}
|
||||
|
||||
static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) {
|
||||
Response R = Response::UseNextDecl(CurDecl);
|
||||
R.ClearRelativeToPrimary = false;
|
||||
return R;
|
||||
}
|
||||
};
|
||||
|
||||
// Retrieve the primary template for a lambda call operator. It's
|
||||
// unfortunate that we only have the mappings of call operators rather
|
||||
// than lambda classes.
|
||||
@ -171,374 +139,396 @@ bool isLambdaEnclosedByTypeAliasDecl(
|
||||
.TraverseType(Underlying);
|
||||
}
|
||||
|
||||
// Add template arguments from a variable template instantiation.
|
||||
Response
|
||||
HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec,
|
||||
MultiLevelTemplateArgumentList &Result,
|
||||
bool SkipForSpecialization) {
|
||||
// For a class-scope explicit specialization, there are no template arguments
|
||||
// at this level, but there may be enclosing template arguments.
|
||||
if (VarTemplSpec->isClassScopeExplicitSpecialization())
|
||||
return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
|
||||
struct TemplateInstantiationArgumentCollecter
|
||||
: DeclVisitor<TemplateInstantiationArgumentCollecter, Decl *> {
|
||||
Sema &S;
|
||||
MultiLevelTemplateArgumentList &Result;
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost;
|
||||
bool RelativeToPrimary;
|
||||
bool ForConstraintInstantiation;
|
||||
|
||||
// We're done when we hit an explicit specialization.
|
||||
if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
|
||||
!isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec))
|
||||
return Response::Done();
|
||||
TemplateInstantiationArgumentCollecter(
|
||||
Sema &S, MultiLevelTemplateArgumentList &Result,
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost,
|
||||
bool RelativeToPrimary, bool ForConstraintInstantiation)
|
||||
: S(S), Result(Result), Innermost(Innermost),
|
||||
RelativeToPrimary(RelativeToPrimary),
|
||||
ForConstraintInstantiation(ForConstraintInstantiation) {}
|
||||
|
||||
// If this variable template specialization was instantiated from a
|
||||
// specialized member that is a variable template, we're done.
|
||||
assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?");
|
||||
llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
|
||||
Specialized = VarTemplSpec->getSpecializedTemplateOrPartial();
|
||||
if (VarTemplatePartialSpecializationDecl *Partial =
|
||||
Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
|
||||
if (!SkipForSpecialization)
|
||||
Result.addOuterTemplateArguments(
|
||||
Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
if (Partial->isMemberSpecialization())
|
||||
return Response::Done();
|
||||
} else {
|
||||
VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>();
|
||||
if (!SkipForSpecialization)
|
||||
Result.addOuterTemplateArguments(
|
||||
Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
if (Tmpl->isMemberSpecialization())
|
||||
return Response::Done();
|
||||
Decl *Done() { return nullptr; }
|
||||
|
||||
Decl *ChangeDecl(const Decl *D) {
|
||||
RelativeToPrimary = false;
|
||||
return const_cast<Decl *>(D);
|
||||
}
|
||||
return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec);
|
||||
}
|
||||
|
||||
// If we have a template template parameter with translation unit context,
|
||||
// then we're performing substitution into a default template argument of
|
||||
// this template template parameter before we've constructed the template
|
||||
// that will own this template template parameter. In this case, we
|
||||
// use empty template parameter lists for all of the outer templates
|
||||
// to avoid performing any substitutions.
|
||||
Response
|
||||
HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP,
|
||||
MultiLevelTemplateArgumentList &Result) {
|
||||
for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I)
|
||||
Result.addOuterTemplateArguments(std::nullopt);
|
||||
return Response::Done();
|
||||
}
|
||||
Decl *ChangeDecl(const DeclContext *DC) {
|
||||
return ChangeDecl(Decl::castFromDeclContext(DC));
|
||||
}
|
||||
|
||||
Response HandlePartialClassTemplateSpec(
|
||||
const ClassTemplatePartialSpecializationDecl *PartialClassTemplSpec,
|
||||
MultiLevelTemplateArgumentList &Result, bool SkipForSpecialization) {
|
||||
if (!SkipForSpecialization)
|
||||
Result.addOuterRetainedLevels(PartialClassTemplSpec->getTemplateDepth());
|
||||
return Response::Done();
|
||||
}
|
||||
Decl *UseNextDecl(const Decl *D) { return ChangeDecl(D->getDeclContext()); }
|
||||
|
||||
void AddInnermostTemplateArguments(const Decl *D) {
|
||||
assert(Innermost);
|
||||
Result.addOuterTemplateArguments(const_cast<Decl *>(D), *Innermost,
|
||||
/*Final=*/false);
|
||||
Innermost.reset();
|
||||
}
|
||||
|
||||
void AddOuterTemplateArguments(const Decl *D, ArrayRef<TemplateArgument> Args,
|
||||
bool Final) {
|
||||
Result.addOuterTemplateArguments(const_cast<Decl *>(D), Args, Final);
|
||||
}
|
||||
|
||||
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTPD) {
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(TTPD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
|
||||
|
||||
for (unsigned Depth = TTPD->getDepth() + 1; Depth--;)
|
||||
AddOuterTemplateArguments(nullptr, std::nullopt, /*Final=*/false);
|
||||
|
||||
return Done();
|
||||
}
|
||||
|
||||
Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *FTD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(FTD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(FTD, FTD->getInjectedTemplateArgs(),
|
||||
/*Final=*/false);
|
||||
|
||||
if (FTD->isMemberSpecialization())
|
||||
return Done();
|
||||
|
||||
if (FTD->getFriendObjectKind())
|
||||
return ChangeDecl(FTD->getLexicalDeclContext());
|
||||
return UseNextDecl(FTD);
|
||||
}
|
||||
|
||||
Decl *VisitVarTemplateDecl(VarTemplateDecl *VTD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(VTD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(VTD, VTD->getInjectedTemplateArgs(),
|
||||
/*Final=*/false);
|
||||
|
||||
if (VTD->isMemberSpecialization())
|
||||
return Done();
|
||||
|
||||
return UseNextDecl(VTD);
|
||||
}
|
||||
|
||||
Decl *VisitVarTemplatePartialSpecializationDecl(
|
||||
VarTemplatePartialSpecializationDecl *VTPSD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(VTPSD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
|
||||
if (VTPSD->isMemberSpecialization())
|
||||
return Done();
|
||||
|
||||
return UseNextDecl(VTPSD);
|
||||
}
|
||||
|
||||
Decl *VisitClassTemplateDecl(ClassTemplateDecl *CTD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(CTD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(CTD, CTD->getInjectedTemplateArgs(),
|
||||
/*Final=*/false);
|
||||
|
||||
if (CTD->isMemberSpecialization())
|
||||
return Done();
|
||||
|
||||
if (CTD->getFriendObjectKind())
|
||||
return ChangeDecl(CTD->getLexicalDeclContext());
|
||||
return UseNextDecl(CTD);
|
||||
}
|
||||
|
||||
Decl *VisitClassTemplatePartialSpecializationDecl(
|
||||
ClassTemplatePartialSpecializationDecl *CTPSD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(CTPSD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
|
||||
if (CTPSD->isMemberSpecialization())
|
||||
return Done();
|
||||
|
||||
return UseNextDecl(CTPSD);
|
||||
}
|
||||
|
||||
Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *TATD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(TATD);
|
||||
else if (ForConstraintInstantiation)
|
||||
AddOuterTemplateArguments(TATD, TATD->getInjectedTemplateArgs(),
|
||||
/*Final=*/false);
|
||||
|
||||
return UseNextDecl(TATD);
|
||||
}
|
||||
|
||||
Decl *VisitConceptDecl(ConceptDecl *CD) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"outer template not instantiated?");
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(CD);
|
||||
|
||||
return UseNextDecl(CD);
|
||||
}
|
||||
|
||||
Decl *VisitFunctionDecl(FunctionDecl *FD) {
|
||||
assert(!FD->getDescribedFunctionTemplate() &&
|
||||
"not for templated declarations");
|
||||
|
||||
if (!RelativeToPrimary) {
|
||||
// Add template arguments from a function template specialization.
|
||||
if (const MemberSpecializationInfo *MSI =
|
||||
FD->getMemberSpecializationInfo();
|
||||
MSI &&
|
||||
MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return Done();
|
||||
|
||||
// This is an implicit instantiation of an explicit specialization. We
|
||||
// don't get any template arguments from this function but might get
|
||||
// some from an enclosing template.
|
||||
if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return UseNextDecl(FD);
|
||||
}
|
||||
|
||||
if (const TemplateArgumentList *TemplateArgs =
|
||||
FD->getTemplateSpecializationArgs()) {
|
||||
// Add the template arguments for this specialization.
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(FD);
|
||||
else
|
||||
AddOuterTemplateArguments(FD, TemplateArgs->asArray(), /*Final=*/false);
|
||||
|
||||
if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization ||
|
||||
(FD->getFriendObjectKind() &&
|
||||
!FD->getPrimaryTemplate()->getFriendObjectKind()))
|
||||
return UseNextDecl(FD);
|
||||
|
||||
// If this function was instantiated from a specialized member that is
|
||||
// a function template, we're done.
|
||||
assert(FD->getPrimaryTemplate() && "No function template?");
|
||||
if (FD->getPrimaryTemplate()->hasMemberSpecialization())
|
||||
return Done();
|
||||
|
||||
// If this function is a generic lambda specialization, we are done.
|
||||
if (!ForConstraintInstantiation &&
|
||||
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD))
|
||||
return Done();
|
||||
}
|
||||
|
||||
// If this is a friend or local declaration and it declares an entity at
|
||||
// namespace scope, take arguments from its lexical parent
|
||||
// instead of its semantic parent, unless of course the pattern we're
|
||||
// instantiating actually comes from the file's context!
|
||||
if ((FD->getFriendObjectKind() || FD->isLocalExternDecl()) &&
|
||||
FD->getNonTransparentDeclContext()->isFileContext()) {
|
||||
return ChangeDecl(FD->getLexicalDeclContext());
|
||||
}
|
||||
|
||||
if (ForConstraintInstantiation && FD->getFriendObjectKind())
|
||||
return ChangeDecl(FD->getLexicalDeclContext());
|
||||
return UseNextDecl(FD);
|
||||
}
|
||||
|
||||
Decl *VisitCXXRecordDecl(CXXRecordDecl *RD) {
|
||||
assert(!RD->getDescribedClassTemplate() &&
|
||||
"not for templated declarations");
|
||||
|
||||
if (const MemberSpecializationInfo *MSI = RD->getMemberSpecializationInfo();
|
||||
MSI &&
|
||||
MSI->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return Done();
|
||||
|
||||
if (ForConstraintInstantiation && RD->getFriendObjectKind() &&
|
||||
RD->getNonTransparentDeclContext()->isFileContext()) {
|
||||
return ChangeDecl(RD->getLexicalDeclContext());
|
||||
}
|
||||
|
||||
// This is to make sure we pick up the VarTemplateSpecializationDecl or the
|
||||
// TypeAliasTemplateDecl that this lambda is defined inside of.
|
||||
if (RD->isLambda()) {
|
||||
if (Decl *LCD = RD->getLambdaContextDecl())
|
||||
return ChangeDecl(LCD);
|
||||
// Retrieve the template arguments for a using alias declaration.
|
||||
// This is necessary for constraint checking, since we always keep
|
||||
// constraints relative to the primary template.
|
||||
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(S);
|
||||
ForConstraintInstantiation && TypeAlias) {
|
||||
if (isLambdaEnclosedByTypeAliasDecl(RD->getLambdaCallOperator(),
|
||||
TypeAlias.PrimaryTypeAliasDecl)) {
|
||||
AddOuterTemplateArguments(TypeAlias.Template,
|
||||
TypeAlias.AssociatedTemplateArguments,
|
||||
/*Final=*/false);
|
||||
// Visit the parent of the current type alias declaration rather than
|
||||
// the lambda thereof.
|
||||
// E.g., in the following example:
|
||||
// struct S {
|
||||
// template <class> using T = decltype([]<Concept> {} ());
|
||||
// };
|
||||
// void foo() {
|
||||
// S::T var;
|
||||
// }
|
||||
// The instantiated lambda expression (which we're visiting at 'var')
|
||||
// has a function DeclContext 'foo' rather than the Record DeclContext
|
||||
// S. This seems to be an oversight to me that we may want to set a
|
||||
// Sema Context from the CXXScopeSpec before substituting into T.
|
||||
return ChangeDecl(TypeAlias.Template->getDeclContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return UseNextDecl(RD);
|
||||
}
|
||||
|
||||
Decl *
|
||||
VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) {
|
||||
// For a class-scope explicit specialization, there are no template
|
||||
// arguments at this level, but there may be enclosing template arguments.
|
||||
if (CTSD->isClassScopeExplicitSpecialization())
|
||||
return UseNextDecl(CTSD);
|
||||
|
||||
// Add template arguments from a class template instantiation.
|
||||
Response
|
||||
HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
|
||||
MultiLevelTemplateArgumentList &Result,
|
||||
bool SkipForSpecialization) {
|
||||
if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) {
|
||||
// We're done when we hit an explicit specialization.
|
||||
if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization &&
|
||||
!isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec))
|
||||
return Response::Done();
|
||||
if (CTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return Done();
|
||||
|
||||
if (!SkipForSpecialization)
|
||||
Result.addOuterTemplateArguments(
|
||||
const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec),
|
||||
ClassTemplSpec->getTemplateInstantiationArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(CTSD);
|
||||
else
|
||||
AddOuterTemplateArguments(CTSD,
|
||||
CTSD->getTemplateInstantiationArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
|
||||
// If this class template specialization was instantiated from a
|
||||
// specialized member that is a class template, we're done.
|
||||
assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?");
|
||||
if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization())
|
||||
return Response::Done();
|
||||
|
||||
// If this was instantiated from a partial template specialization, we need
|
||||
// to get the next level of declaration context from the partial
|
||||
// specialization, as the ClassTemplateSpecializationDecl's
|
||||
// DeclContext/LexicalDeclContext will be for the primary template.
|
||||
if (auto *InstFromPartialTempl = ClassTemplSpec->getSpecializedTemplateOrPartial()
|
||||
.dyn_cast<ClassTemplatePartialSpecializationDecl *>())
|
||||
return Response::ChangeDecl(InstFromPartialTempl->getLexicalDeclContext());
|
||||
}
|
||||
return Response::UseNextDecl(ClassTemplSpec);
|
||||
}
|
||||
|
||||
Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
|
||||
MultiLevelTemplateArgumentList &Result,
|
||||
const FunctionDecl *Pattern, bool RelativeToPrimary,
|
||||
bool ForConstraintInstantiation,
|
||||
bool ForDefaultArgumentSubstitution) {
|
||||
// Add template arguments from a function template specialization.
|
||||
if (!RelativeToPrimary &&
|
||||
Function->getTemplateSpecializationKindForInstantiation() ==
|
||||
TSK_ExplicitSpecialization)
|
||||
return Response::Done();
|
||||
|
||||
if (!RelativeToPrimary &&
|
||||
Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
|
||||
// This is an implicit instantiation of an explicit specialization. We
|
||||
// don't get any template arguments from this function but might get
|
||||
// some from an enclosing template.
|
||||
return Response::UseNextDecl(Function);
|
||||
} else if (const TemplateArgumentList *TemplateArgs =
|
||||
Function->getTemplateSpecializationArgs()) {
|
||||
// Add the template arguments for this specialization.
|
||||
Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function),
|
||||
TemplateArgs->asArray(),
|
||||
/*Final=*/false);
|
||||
|
||||
if (RelativeToPrimary &&
|
||||
(Function->getTemplateSpecializationKind() ==
|
||||
TSK_ExplicitSpecialization ||
|
||||
(Function->getFriendObjectKind() &&
|
||||
!Function->getPrimaryTemplate()->getFriendObjectKind())))
|
||||
return Response::UseNextDecl(Function);
|
||||
|
||||
// If this function was instantiated from a specialized member that is
|
||||
// a function template, we're done.
|
||||
assert(Function->getPrimaryTemplate() && "No function template?");
|
||||
if (!ForDefaultArgumentSubstitution &&
|
||||
Function->getPrimaryTemplate()->isMemberSpecialization())
|
||||
return Response::Done();
|
||||
|
||||
// If this function is a generic lambda specialization, we are done.
|
||||
if (!ForConstraintInstantiation &&
|
||||
isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function))
|
||||
return Response::Done();
|
||||
|
||||
} else if (Function->getDescribedFunctionTemplate()) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"Outer template not instantiated?");
|
||||
}
|
||||
// If this is a friend or local declaration and it declares an entity at
|
||||
// namespace scope, take arguments from its lexical parent
|
||||
// instead of its semantic parent, unless of course the pattern we're
|
||||
// instantiating actually comes from the file's context!
|
||||
if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) &&
|
||||
Function->getNonTransparentDeclContext()->isFileContext() &&
|
||||
(!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) {
|
||||
return Response::ChangeDecl(Function->getLexicalDeclContext());
|
||||
}
|
||||
|
||||
if (ForConstraintInstantiation && Function->getFriendObjectKind())
|
||||
return Response::ChangeDecl(Function->getLexicalDeclContext());
|
||||
return Response::UseNextDecl(Function);
|
||||
}
|
||||
|
||||
Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD,
|
||||
MultiLevelTemplateArgumentList &Result) {
|
||||
if (!isa<ClassTemplateSpecializationDecl>(FTD->getDeclContext())) {
|
||||
Result.addOuterTemplateArguments(
|
||||
const_cast<FunctionTemplateDecl *>(FTD),
|
||||
const_cast<FunctionTemplateDecl *>(FTD)->getInjectedTemplateArgs(),
|
||||
/*Final=*/false);
|
||||
|
||||
NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier();
|
||||
|
||||
while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) {
|
||||
if (NNS->isInstantiationDependent()) {
|
||||
if (const auto *TSTy = Ty->getAs<TemplateSpecializationType>()) {
|
||||
ArrayRef<TemplateArgument> Arguments = TSTy->template_arguments();
|
||||
// Prefer template arguments from the injected-class-type if possible.
|
||||
// For example,
|
||||
// ```cpp
|
||||
// template <class... Pack> struct S {
|
||||
// template <class T> void foo();
|
||||
// };
|
||||
// template <class... Pack> template <class T>
|
||||
// ^^^^^^^^^^^^^ InjectedTemplateArgs
|
||||
// They're of kind TemplateArgument::Pack, not of
|
||||
// TemplateArgument::Type.
|
||||
// void S<Pack...>::foo() {}
|
||||
// ^^^^^^^
|
||||
// TSTy->template_arguments() (which are of PackExpansionType)
|
||||
// ```
|
||||
// This meets the contract in
|
||||
// TreeTransform::TryExpandParameterPacks that the template arguments
|
||||
// for unexpanded parameters should be of a Pack kind.
|
||||
if (TSTy->isCurrentInstantiation()) {
|
||||
auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl();
|
||||
if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate())
|
||||
Arguments = CTD->getInjectedTemplateArgs();
|
||||
else if (auto *Specialization =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(RD))
|
||||
Arguments =
|
||||
Specialization->getTemplateInstantiationArgs().asArray();
|
||||
}
|
||||
Result.addOuterTemplateArguments(
|
||||
TSTy->getTemplateName().getAsTemplateDecl(), Arguments,
|
||||
/*Final=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
NNS = NNS->getPrefix();
|
||||
assert(CTSD->getSpecializedTemplate() && "No class template?");
|
||||
llvm::PointerUnion<ClassTemplateDecl *,
|
||||
ClassTemplatePartialSpecializationDecl *>
|
||||
Specialized = CTSD->getSpecializedTemplateOrPartial();
|
||||
if (auto *CTPSD =
|
||||
Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
|
||||
if (CTPSD->hasMemberSpecialization())
|
||||
return Done();
|
||||
} else {
|
||||
auto *CTD = Specialized.get<ClassTemplateDecl *>();
|
||||
if (CTD->hasMemberSpecialization())
|
||||
return Done();
|
||||
}
|
||||
return UseNextDecl(CTSD);
|
||||
}
|
||||
|
||||
return Response::ChangeDecl(FTD->getLexicalDeclContext());
|
||||
}
|
||||
Decl *
|
||||
VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) {
|
||||
// For a class-scope explicit specialization, there are no template
|
||||
// arguments at this level, but there may be enclosing template arguments.
|
||||
if (VTSD->isClassScopeExplicitSpecialization())
|
||||
return UseNextDecl(VTSD);
|
||||
|
||||
Response HandleRecordDecl(Sema &SemaRef, const CXXRecordDecl *Rec,
|
||||
MultiLevelTemplateArgumentList &Result,
|
||||
ASTContext &Context,
|
||||
bool ForConstraintInstantiation) {
|
||||
if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) {
|
||||
assert(
|
||||
(ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) &&
|
||||
"Outer template not instantiated?");
|
||||
if (ClassTemplate->isMemberSpecialization())
|
||||
return Response::Done();
|
||||
if (ForConstraintInstantiation)
|
||||
Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec),
|
||||
ClassTemplate->getInjectedTemplateArgs(),
|
||||
/*Final=*/false);
|
||||
}
|
||||
// We're done when we hit an explicit specialization.
|
||||
if (VTSD->getSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return Done();
|
||||
|
||||
if (const MemberSpecializationInfo *MSInfo =
|
||||
Rec->getMemberSpecializationInfo())
|
||||
if (MSInfo->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return Response::Done();
|
||||
if (Innermost)
|
||||
AddInnermostTemplateArguments(VTSD);
|
||||
else
|
||||
AddOuterTemplateArguments(VTSD,
|
||||
VTSD->getTemplateInstantiationArgs().asArray(),
|
||||
/*Final=*/false);
|
||||
|
||||
bool IsFriend = Rec->getFriendObjectKind() ||
|
||||
(Rec->getDescribedClassTemplate() &&
|
||||
Rec->getDescribedClassTemplate()->getFriendObjectKind());
|
||||
if (ForConstraintInstantiation && IsFriend &&
|
||||
Rec->getNonTransparentDeclContext()->isFileContext()) {
|
||||
return Response::ChangeDecl(Rec->getLexicalDeclContext());
|
||||
}
|
||||
|
||||
// This is to make sure we pick up the VarTemplateSpecializationDecl or the
|
||||
// TypeAliasTemplateDecl that this lambda is defined inside of.
|
||||
if (Rec->isLambda()) {
|
||||
if (const Decl *LCD = Rec->getLambdaContextDecl())
|
||||
return Response::ChangeDecl(LCD);
|
||||
// Retrieve the template arguments for a using alias declaration.
|
||||
// This is necessary for constraint checking, since we always keep
|
||||
// constraints relative to the primary template.
|
||||
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(SemaRef);
|
||||
ForConstraintInstantiation && TypeAlias) {
|
||||
if (isLambdaEnclosedByTypeAliasDecl(Rec->getLambdaCallOperator(),
|
||||
TypeAlias.PrimaryTypeAliasDecl)) {
|
||||
Result.addOuterTemplateArguments(TypeAlias.Template,
|
||||
TypeAlias.AssociatedTemplateArguments,
|
||||
/*Final=*/false);
|
||||
// Visit the parent of the current type alias declaration rather than
|
||||
// the lambda thereof.
|
||||
// E.g., in the following example:
|
||||
// struct S {
|
||||
// template <class> using T = decltype([]<Concept> {} ());
|
||||
// };
|
||||
// void foo() {
|
||||
// S::T var;
|
||||
// }
|
||||
// The instantiated lambda expression (which we're visiting at 'var')
|
||||
// has a function DeclContext 'foo' rather than the Record DeclContext
|
||||
// S. This seems to be an oversight to me that we may want to set a
|
||||
// Sema Context from the CXXScopeSpec before substituting into T.
|
||||
return Response::ChangeDecl(TypeAlias.Template->getDeclContext());
|
||||
}
|
||||
// If this variable template specialization was instantiated from a
|
||||
// specialized member that is a variable template, we're done.
|
||||
assert(VTSD->getSpecializedTemplate() && "No variable template?");
|
||||
llvm::PointerUnion<VarTemplateDecl *,
|
||||
VarTemplatePartialSpecializationDecl *>
|
||||
Specialized = VTSD->getSpecializedTemplateOrPartial();
|
||||
if (auto *VTPSD =
|
||||
Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
|
||||
if (VTPSD->hasMemberSpecialization())
|
||||
return Done();
|
||||
} else {
|
||||
auto *VTD = Specialized.get<VarTemplateDecl *>();
|
||||
if (VTD->hasMemberSpecialization())
|
||||
return Done();
|
||||
}
|
||||
return UseNextDecl(VTSD);
|
||||
}
|
||||
|
||||
return Response::UseNextDecl(Rec);
|
||||
}
|
||||
Decl *VisitImplicitConceptSpecializationDecl(
|
||||
ImplicitConceptSpecializationDecl *ICSD) {
|
||||
AddOuterTemplateArguments(ICSD, ICSD->getTemplateArguments(),
|
||||
/*Final=*/false);
|
||||
return UseNextDecl(ICSD);
|
||||
}
|
||||
|
||||
Response HandleImplicitConceptSpecializationDecl(
|
||||
const ImplicitConceptSpecializationDecl *CSD,
|
||||
MultiLevelTemplateArgumentList &Result) {
|
||||
Result.addOuterTemplateArguments(
|
||||
const_cast<ImplicitConceptSpecializationDecl *>(CSD),
|
||||
CSD->getTemplateArguments(),
|
||||
/*Final=*/false);
|
||||
return Response::UseNextDecl(CSD);
|
||||
}
|
||||
Decl *VisitDecl(Decl *D) {
|
||||
if (D->isFileContextDecl())
|
||||
return Done();
|
||||
|
||||
if (isa<DeclContext>(D))
|
||||
RelativeToPrimary = false;
|
||||
|
||||
return UseNextDecl(D);
|
||||
}
|
||||
|
||||
Decl *Visit(Decl *D) {
|
||||
if (TemplateDecl *TD = D->getDescribedTemplate())
|
||||
D = TD;
|
||||
return DeclVisitor::Visit(D);
|
||||
}
|
||||
};
|
||||
|
||||
Response HandleGenericDeclContext(const Decl *CurDecl) {
|
||||
return Response::UseNextDecl(CurDecl);
|
||||
}
|
||||
} // namespace TemplateInstArgsHelpers
|
||||
} // namespace
|
||||
|
||||
MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
|
||||
const NamedDecl *ND, const DeclContext *DC, bool Final,
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
|
||||
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
|
||||
bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
|
||||
bool ForConstraintInstantiation) {
|
||||
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
|
||||
// Accumulate the set of template argument lists in this structure.
|
||||
MultiLevelTemplateArgumentList Result;
|
||||
|
||||
using namespace TemplateInstArgsHelpers;
|
||||
const Decl *CurDecl = ND;
|
||||
|
||||
if (!CurDecl)
|
||||
CurDecl = Decl::castFromDeclContext(DC);
|
||||
|
||||
if (Innermost) {
|
||||
Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), *Innermost,
|
||||
Final);
|
||||
// Populate placeholder template arguments for TemplateTemplateParmDecls.
|
||||
// This is essential for the case e.g.
|
||||
//
|
||||
// template <class> concept Concept = false;
|
||||
// template <template <Concept C> class T> void foo(T<int>)
|
||||
//
|
||||
// where parameter C has a depth of 1 but the substituting argument `int`
|
||||
// has a depth of 0.
|
||||
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
|
||||
HandleDefaultTempArgIntoTempTempParam(TTP, Result);
|
||||
CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
|
||||
}
|
||||
|
||||
while (!CurDecl->isFileContextDecl()) {
|
||||
Response R;
|
||||
if (const auto *VarTemplSpec =
|
||||
dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) {
|
||||
R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization);
|
||||
} else if (const auto *PartialClassTemplSpec =
|
||||
dyn_cast<ClassTemplatePartialSpecializationDecl>(CurDecl)) {
|
||||
R = HandlePartialClassTemplateSpec(PartialClassTemplSpec, Result,
|
||||
SkipForSpecialization);
|
||||
} else if (const auto *ClassTemplSpec =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) {
|
||||
R = HandleClassTemplateSpec(ClassTemplSpec, Result,
|
||||
SkipForSpecialization);
|
||||
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
|
||||
R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
|
||||
ForConstraintInstantiation,
|
||||
ForDefaultArgumentSubstitution);
|
||||
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
|
||||
R = HandleRecordDecl(*this, Rec, Result, Context,
|
||||
ForConstraintInstantiation);
|
||||
} else if (const auto *CSD =
|
||||
dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
|
||||
R = HandleImplicitConceptSpecializationDecl(CSD, Result);
|
||||
} else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) {
|
||||
R = HandleFunctionTemplateDecl(FTD, Result);
|
||||
} else if (const auto *CTD = dyn_cast<ClassTemplateDecl>(CurDecl)) {
|
||||
R = Response::ChangeDecl(CTD->getLexicalDeclContext());
|
||||
} else if (!isa<DeclContext>(CurDecl)) {
|
||||
R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
|
||||
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
|
||||
R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
|
||||
}
|
||||
} else {
|
||||
R = HandleGenericDeclContext(CurDecl);
|
||||
}
|
||||
|
||||
if (R.IsDone)
|
||||
return Result;
|
||||
if (R.ClearRelativeToPrimary)
|
||||
RelativeToPrimary = false;
|
||||
assert(R.NextDecl);
|
||||
CurDecl = R.NextDecl;
|
||||
}
|
||||
|
||||
TemplateInstantiationArgumentCollecter Collecter(
|
||||
*this, Result, Innermost, RelativeToPrimary, ForConstraintInstantiation);
|
||||
do {
|
||||
CurDecl = Collecter.Visit(const_cast<Decl *>(CurDecl));
|
||||
} while (CurDecl);
|
||||
return Result;
|
||||
}
|
||||
|
||||
@ -1673,10 +1663,8 @@ namespace {
|
||||
|
||||
CXXRecordDecl::LambdaDependencyKind
|
||||
ComputeLambdaDependency(LambdaScopeInfo *LSI) {
|
||||
if (auto TypeAlias =
|
||||
TemplateInstArgsHelpers::getEnclosingTypeAliasTemplateDecl(
|
||||
getSema());
|
||||
TypeAlias && TemplateInstArgsHelpers::isLambdaEnclosedByTypeAliasDecl(
|
||||
if (auto TypeAlias = getEnclosingTypeAliasTemplateDecl(getSema());
|
||||
TypeAlias && isLambdaEnclosedByTypeAliasDecl(
|
||||
LSI->CallOperator, TypeAlias.PrimaryTypeAliasDecl)) {
|
||||
unsigned TypeAliasDeclDepth = TypeAlias.Template->getTemplateDepth();
|
||||
if (TypeAliasDeclDepth >= TemplateArgs.getNumSubstitutedLevels())
|
||||
@ -1721,8 +1709,8 @@ namespace {
|
||||
// RecoveryExpr that wraps the uninstantiated default argument so
|
||||
// that downstream diagnostics are omitted.
|
||||
ExprResult ErrorResult = SemaRef.CreateRecoveryExpr(
|
||||
UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(),
|
||||
{ UninstExpr }, UninstExpr->getType());
|
||||
UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr},
|
||||
UninstExpr->getType());
|
||||
if (ErrorResult.isUsable())
|
||||
PVD->setDefaultArg(ErrorResult.get());
|
||||
}
|
||||
@ -4128,31 +4116,25 @@ getPatternForClassTemplateSpecialization(
|
||||
|
||||
CXXRecordDecl *Pattern = nullptr;
|
||||
Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
|
||||
if (auto *PartialSpec =
|
||||
Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
|
||||
// Instantiate using the best class template partial specialization.
|
||||
while (PartialSpec->getInstantiatedFromMember()) {
|
||||
// If we've found an explicit specialization of this class template,
|
||||
// stop here and use that as the pattern.
|
||||
if (PartialSpec->isMemberSpecialization())
|
||||
if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
|
||||
while (!CTD->hasMemberSpecialization()) {
|
||||
if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
|
||||
CTD = NewCTD;
|
||||
else
|
||||
break;
|
||||
|
||||
PartialSpec = PartialSpec->getInstantiatedFromMember();
|
||||
}
|
||||
Pattern = PartialSpec;
|
||||
} else {
|
||||
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
|
||||
while (Template->getInstantiatedFromMemberTemplate()) {
|
||||
// If we've found an explicit specialization of this class template,
|
||||
// stop here and use that as the pattern.
|
||||
if (Template->isMemberSpecialization())
|
||||
Pattern = CTD->getTemplatedDecl();
|
||||
} else if (auto *CTPSD =
|
||||
Specialized
|
||||
.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
|
||||
while (!CTPSD->hasMemberSpecialization()) {
|
||||
if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
|
||||
CTPSD = NewCTPSD;
|
||||
else
|
||||
break;
|
||||
|
||||
Template = Template->getInstantiatedFromMemberTemplate();
|
||||
}
|
||||
Pattern = Template->getTemplatedDecl();
|
||||
Pattern = CTPSD;
|
||||
}
|
||||
|
||||
return Pattern;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "TreeTransform.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTLambda.h"
|
||||
#include "clang/AST/ASTMutationListener.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/DeclVisitor.h"
|
||||
@ -4688,6 +4689,36 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
|
||||
ParmVarDecl *Param) {
|
||||
assert(Param->hasUninstantiatedDefaultArg());
|
||||
|
||||
NamedDecl *Pattern = FD;
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost;
|
||||
|
||||
// C++ [dcl.fct.default]p4
|
||||
// For non-template functions, default arguments can be added in later
|
||||
// declarations of a function that inhabit the same scope.
|
||||
//
|
||||
// C++ [dcl.fct.default]p6
|
||||
// Except for member functions of templated classes, the default arguments
|
||||
// in a member function definition that appears outside of the class
|
||||
// definition are added to the set of default arguments provided by the
|
||||
// member function declaration in the class definition; the program is
|
||||
// ill-formed if a default constructor, copy or move constructor, or copy
|
||||
// or move assignment operator is so declared. Default arguments for a
|
||||
// member function of a templated class shall be specified on the initial
|
||||
// declaration of the member function within the templated class.
|
||||
//
|
||||
// We need to collect the template arguments from the context of the function
|
||||
// where the default argument was defined. For a specialization of a function
|
||||
// template explicitly specialized for an implicit instantiation of a class
|
||||
// template, that context is the (implicitly instantiated) declaration in the
|
||||
// definition of the class template specialization.
|
||||
if (FD->isCXXClassMember() &&
|
||||
!isGenericLambdaCallOperatorOrStaticInvokerSpecialization(FD)) {
|
||||
if (FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) {
|
||||
Pattern = FTD->getFirstDecl();
|
||||
Innermost = FD->getTemplateSpecializationArgs()->asArray();
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the expression.
|
||||
//
|
||||
// FIXME: Pass in a correct Pattern argument, otherwise
|
||||
@ -4705,12 +4736,10 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
|
||||
//
|
||||
// template<typename T>
|
||||
// A<T> Foo(int a = A<T>::FooImpl());
|
||||
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
|
||||
FD, FD->getLexicalDeclContext(),
|
||||
/*Final=*/false, /*Innermost=*/std::nullopt,
|
||||
/*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
|
||||
/*ForDefaultArgumentSubstitution=*/true);
|
||||
MultiLevelTemplateArgumentList TemplateArgs =
|
||||
getTemplateInstantiationArgs(Pattern, Pattern->getLexicalDeclContext(),
|
||||
/*Final=*/false, Innermost,
|
||||
/*RelativeToPrimary=*/true);
|
||||
|
||||
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
|
||||
return true;
|
||||
@ -4751,7 +4780,7 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||
MultiLevelTemplateArgumentList TemplateArgs =
|
||||
getTemplateInstantiationArgs(Decl, Decl->getLexicalDeclContext(),
|
||||
/*Final=*/false, /*Innermost=*/std::nullopt,
|
||||
/*RelativeToPrimary*/ true);
|
||||
/*RelativeToPrimary=*/true);
|
||||
|
||||
// FIXME: We can't use getTemplateInstantiationPattern(false) in general
|
||||
// here, because for a non-defining friend declaration in a class template,
|
||||
@ -5199,8 +5228,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
||||
SetDeclDefaulted(Function, PatternDecl->getLocation());
|
||||
} else {
|
||||
MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
|
||||
Function, Function->getLexicalDeclContext(), /*Final=*/false,
|
||||
/*Innermost=*/std::nullopt, false, PatternDecl);
|
||||
Function, Function->getLexicalDeclContext());
|
||||
|
||||
// Substitute into the qualifier; we can get a substitution failure here
|
||||
// through evil use of alias templates.
|
||||
|
@ -10003,7 +10003,8 @@ void ASTReader::finishPendingActions() {
|
||||
|
||||
auto RTD = cast<RedeclarableTemplateDecl>(D)->getCanonicalDecl();
|
||||
for (auto *R = getMostRecentExistingDecl(RTD); R; R = R->getPreviousDecl())
|
||||
cast<RedeclarableTemplateDecl>(R)->Common = RTD->Common;
|
||||
cast<RedeclarableTemplateDecl>(R)->setCommonPtr(
|
||||
RTD->getCommonPtrInternal());
|
||||
}
|
||||
PendingDefinitions.clear();
|
||||
|
||||
|
@ -2416,11 +2416,13 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
||||
// Make sure we've allocated the Common pointer first. We do this before
|
||||
// VisitTemplateDecl so that getCommonPtr() can be used during initialization.
|
||||
RedeclarableTemplateDecl *CanonD = D->getCanonicalDecl();
|
||||
if (!CanonD->Common) {
|
||||
CanonD->Common = CanonD->newCommon(Reader.getContext());
|
||||
if (!CanonD->getCommonPtrInternal()) {
|
||||
CanonD->setCommonPtr(CanonD->newCommon(Reader.getContext()));
|
||||
Reader.PendingDefinitions.insert(CanonD);
|
||||
}
|
||||
D->Common = CanonD->Common;
|
||||
D->setCommonPtr(CanonD->getCommonPtrInternal());
|
||||
if (Record.readInt())
|
||||
D->setMemberSpecialization();
|
||||
|
||||
// If this is the first declaration of the template, fill in the information
|
||||
// for the 'common' pointer.
|
||||
@ -2429,8 +2431,6 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
||||
assert(RTD->getKind() == D->getKind() &&
|
||||
"InstantiatedFromMemberTemplate kind mismatch");
|
||||
D->setInstantiatedFromMemberTemplate(RTD);
|
||||
if (Record.readInt())
|
||||
D->setMemberSpecialization();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2562,12 +2562,12 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
|
||||
D->TemplateParams = Params;
|
||||
|
||||
RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D);
|
||||
D->InstantiatedFromMember.setInt(Record.readInt());
|
||||
|
||||
// These are read/set from/to the first declaration.
|
||||
if (ThisDeclID == Redecl.getFirstID()) {
|
||||
D->InstantiatedFromMember.setPointer(
|
||||
readDeclAs<ClassTemplatePartialSpecializationDecl>());
|
||||
D->InstantiatedFromMember.setInt(Record.readInt());
|
||||
readDeclAs<ClassTemplatePartialSpecializationDecl>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2660,12 +2660,12 @@ void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl(
|
||||
D->TemplateParams = Params;
|
||||
|
||||
RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D);
|
||||
D->InstantiatedFromMember.setInt(Record.readInt());
|
||||
|
||||
// These are read/set from/to the first declaration.
|
||||
if (ThisDeclID == Redecl.getFirstID()) {
|
||||
D->InstantiatedFromMember.setPointer(
|
||||
readDeclAs<VarTemplatePartialSpecializationDecl>());
|
||||
D->InstantiatedFromMember.setInt(Record.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
@ -2888,7 +2888,7 @@ void ASTDeclReader::mergeRedeclarableTemplate(RedeclarableTemplateDecl *D,
|
||||
// If we merged the template with a prior declaration chain, merge the
|
||||
// common pointer.
|
||||
// FIXME: Actually merge here, don't just overwrite.
|
||||
D->Common = D->getCanonicalDecl()->Common;
|
||||
D->setCommonPtr(D->getCanonicalDecl()->getCommonPtrInternal());
|
||||
}
|
||||
|
||||
/// "Cast" to type T, asserting if we don't have an implicit conversion.
|
||||
|
@ -1713,14 +1713,13 @@ void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
|
||||
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
|
||||
VisitRedeclarable(D);
|
||||
|
||||
Record.push_back(D->isMemberSpecialization());
|
||||
|
||||
// Emit data to initialize CommonOrPrev before VisitTemplateDecl so that
|
||||
// getCommonPtr() can be used while this is still initializing.
|
||||
if (D->isFirstDecl()) {
|
||||
if (D->isFirstDecl())
|
||||
// This declaration owns the 'common' pointer, so serialize that data now.
|
||||
Record.AddDeclRef(D->getInstantiatedFromMemberTemplate());
|
||||
if (D->getInstantiatedFromMemberTemplate())
|
||||
Record.push_back(D->isMemberSpecialization());
|
||||
}
|
||||
|
||||
VisitTemplateDecl(D);
|
||||
Record.push_back(D->getIdentifierNamespace());
|
||||
@ -1806,11 +1805,10 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
|
||||
|
||||
VisitClassTemplateSpecializationDecl(D);
|
||||
|
||||
Record.push_back(D->isMemberSpecialization());
|
||||
// These are read/set from/to the first declaration.
|
||||
if (D->getPreviousDecl() == nullptr) {
|
||||
if (D->isFirstDecl())
|
||||
Record.AddDeclRef(D->getInstantiatedFromMember());
|
||||
Record.push_back(D->isMemberSpecialization());
|
||||
}
|
||||
|
||||
Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION;
|
||||
}
|
||||
@ -1874,12 +1872,11 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl(
|
||||
Record.AddTemplateParameterList(D->getTemplateParameters());
|
||||
|
||||
VisitVarTemplateSpecializationDecl(D);
|
||||
Record.push_back(D->isMemberSpecialization());
|
||||
|
||||
// These are read/set from/to the first declaration.
|
||||
if (D->getPreviousDecl() == nullptr) {
|
||||
if (D->isFirstDecl())
|
||||
Record.AddDeclRef(D->getInstantiatedFromMember());
|
||||
Record.push_back(D->isMemberSpecialization());
|
||||
}
|
||||
|
||||
Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION;
|
||||
}
|
||||
|
175
clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
Normal file
175
clang/test/CXX/temp/temp.constr/temp.constr.decl/p4.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
template<typename T>
|
||||
concept D = true;
|
||||
|
||||
template<typename T>
|
||||
struct A {
|
||||
template<typename U, bool V>
|
||||
void f() requires V;
|
||||
|
||||
template<>
|
||||
void f<short, true>();
|
||||
|
||||
template<D U>
|
||||
void g();
|
||||
|
||||
template<typename U, bool V> requires V
|
||||
struct B;
|
||||
|
||||
template<typename U, bool V> requires V
|
||||
struct B<U*, V>;
|
||||
|
||||
template<>
|
||||
struct B<short, true>;
|
||||
|
||||
template<D U>
|
||||
struct C;
|
||||
|
||||
template<D U>
|
||||
struct C<U*>;
|
||||
|
||||
template<typename U, bool V> requires V
|
||||
static int x;
|
||||
|
||||
template<typename U, bool V> requires V
|
||||
static int x<U*, V>;
|
||||
|
||||
template<>
|
||||
int x<short, true>;
|
||||
|
||||
template<D U>
|
||||
static int y;
|
||||
|
||||
template<D U>
|
||||
static int y<U*>;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V>
|
||||
void A<T>::f() requires V { }
|
||||
|
||||
template<typename T>
|
||||
template<D U>
|
||||
void A<T>::g() { }
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V> requires V
|
||||
struct A<T>::B { };
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V> requires V
|
||||
struct A<T>::B<U*, V> { };
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V> requires V
|
||||
struct A<T>::B<U&, V> { };
|
||||
|
||||
template<typename T>
|
||||
template<D U>
|
||||
struct A<T>::C { };
|
||||
|
||||
template<typename T>
|
||||
template<D U>
|
||||
struct A<T>::C<U*> { };
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V> requires V
|
||||
int A<T>::x = 0;
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V> requires V
|
||||
int A<T>::x<U*, V> = 0;
|
||||
|
||||
template<typename T>
|
||||
template<typename U, bool V> requires V
|
||||
int A<T>::x<U&, V> = 0;
|
||||
|
||||
template<typename T>
|
||||
template<D U>
|
||||
int A<T>::y = 0;
|
||||
|
||||
template<typename T>
|
||||
template<D U>
|
||||
int A<T>::y<U*> = 0;
|
||||
|
||||
template<>
|
||||
template<typename U, bool V>
|
||||
void A<short>::f() requires V;
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void A<short>::f<int, true>();
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void A<void>::f<int, true>();
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
void A<short>::g();
|
||||
|
||||
template<>
|
||||
template<typename U, bool V> requires V
|
||||
struct A<int>::B;
|
||||
|
||||
template<>
|
||||
template<>
|
||||
struct A<int>::B<int, true>;
|
||||
|
||||
template<>
|
||||
template<>
|
||||
struct A<void>::B<int, true>;
|
||||
|
||||
template<>
|
||||
template<typename U, bool V> requires V
|
||||
struct A<int>::B<U*, V>;
|
||||
|
||||
template<>
|
||||
template<typename U, bool V> requires V
|
||||
struct A<int>::B<U&, V>;
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
struct A<int>::C;
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
struct A<int>::C<U*>;
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
struct A<int>::C<U&>;
|
||||
|
||||
template<>
|
||||
template<typename U, bool V> requires V
|
||||
int A<long>::x;
|
||||
|
||||
template<>
|
||||
template<>
|
||||
int A<long>::x<int, true>;
|
||||
|
||||
template<>
|
||||
template<>
|
||||
int A<void>::x<int, true>;
|
||||
|
||||
template<>
|
||||
template<typename U, bool V> requires V
|
||||
int A<long>::x<U*, V>;
|
||||
|
||||
template<>
|
||||
template<typename U, bool V> requires V
|
||||
int A<long>::x<U&, V>;
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
int A<long>::y;
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
int A<long>::y<U*>;
|
||||
|
||||
template<>
|
||||
template<D U>
|
||||
int A<long>::y<U&>;
|
228
clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
Normal file
228
clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
|
||||
|
||||
namespace Undefined {
|
||||
template<typename T>
|
||||
struct A {
|
||||
template<typename U>
|
||||
static constexpr int f(); // expected-note {{declared here}}
|
||||
|
||||
template<typename U>
|
||||
static const int x; // expected-note {{declared here}}
|
||||
|
||||
template<typename U>
|
||||
static const int x<U*>; // expected-note {{declared here}}
|
||||
|
||||
template<typename U>
|
||||
struct B; // expected-note {{template is declared here}}
|
||||
|
||||
template<typename U>
|
||||
struct B<U*>; // expected-note {{template is declared here}}
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<short>::f() {
|
||||
return A<long>::f<U>();
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<short>::x = A<long>::x<U>;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<short>::x<U*> = A<long>::x<U*>;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<short>::B<U*> {
|
||||
static constexpr int y = A<long>::B<U*>::y;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<short>::B {
|
||||
static constexpr int y = A<long>::B<U>::y;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<long>::f() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<long>::x = 1;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<long>::x<U*> = 2;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<long>::B {
|
||||
static constexpr int y = 1;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<long>::B<U*> {
|
||||
static constexpr int y = 2;
|
||||
};
|
||||
|
||||
static_assert(A<int>::f<int>() == 0); // expected-error {{static assertion expression is not an integral constant expression}}
|
||||
// expected-note@-1 {{undefined function 'f<int>' cannot be used in a constant expression}}
|
||||
static_assert(A<int>::x<int> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
|
||||
// expected-note@-1 {{initializer of 'x<int>' is unknown}}
|
||||
static_assert(A<int>::x<int*> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
|
||||
// expected-note@-1 {{initializer of 'x<int *>' is unknown}}
|
||||
static_assert(A<int>::B<int>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int>'}}
|
||||
static_assert(A<int>::B<int*>::y == 0); // expected-error {{implicit instantiation of undefined template 'Undefined::A<int>::B<int *>'}}
|
||||
|
||||
static_assert(A<short>::f<int>() == 1);
|
||||
static_assert(A<short>::x<int> == 1);
|
||||
static_assert(A<short>::x<int*> == 2);
|
||||
static_assert(A<short>::B<int>::y == 1);
|
||||
static_assert(A<short>::B<int*>::y == 2);
|
||||
} // namespace Undefined
|
||||
|
||||
namespace Defined {
|
||||
template<typename T>
|
||||
struct A {
|
||||
template<typename U>
|
||||
static constexpr int f() {
|
||||
return 0;
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
static const int x = 0;
|
||||
|
||||
template<typename U>
|
||||
static const int x<U*> = 0;
|
||||
|
||||
template<typename U>
|
||||
struct B {
|
||||
static constexpr int y = 0;
|
||||
};
|
||||
|
||||
template<typename U>
|
||||
struct B<U*> {
|
||||
static constexpr int y = 0;
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<short>::f() {
|
||||
return A<long>::f<U>();
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<short>::x = A<long>::x<U>;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<short>::x<U*> = A<long>::x<U*>;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<short>::B<U*> {
|
||||
static constexpr int y = A<long>::B<U*>::y;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<short>::B {
|
||||
static constexpr int y = A<long>::B<U>::y;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<long>::f() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<long>::x = 1;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
constexpr int A<long>::x<U*> = 2;
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<long>::B {
|
||||
static constexpr int y = 1;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename U>
|
||||
struct A<long>::B<U*> {
|
||||
static constexpr int y = 2;
|
||||
};
|
||||
|
||||
static_assert(A<int>::f<int>() == 0);
|
||||
static_assert(A<int>::x<int> == 0);
|
||||
static_assert(A<int>::x<int*> == 0);
|
||||
static_assert(A<int>::B<int>::y == 0);
|
||||
static_assert(A<int>::B<int*>::y == 0);
|
||||
|
||||
static_assert(A<short>::f<int>() == 1);
|
||||
static_assert(A<short>::x<int> == 1);
|
||||
static_assert(A<short>::x<int*> == 2);
|
||||
static_assert(A<short>::B<int>::y == 1);
|
||||
static_assert(A<short>::B<int*>::y == 2);
|
||||
} // namespace Defined
|
||||
|
||||
namespace Dependent {
|
||||
template<int I>
|
||||
struct A {
|
||||
template<int J>
|
||||
static constexpr int f();
|
||||
|
||||
template<int J>
|
||||
static const int x;
|
||||
|
||||
template<int J>
|
||||
struct B;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<int J>
|
||||
constexpr int A<0>::f() {
|
||||
return A<1>::f<J>();
|
||||
}
|
||||
|
||||
template<>
|
||||
template<int J>
|
||||
constexpr int A<1>::f() {
|
||||
return J;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<int J>
|
||||
constexpr int A<0>::x = A<1>::x<J>;
|
||||
|
||||
template<>
|
||||
template<int J>
|
||||
constexpr int A<1>::x = J;
|
||||
|
||||
template<>
|
||||
template<int J>
|
||||
struct A<0>::B {
|
||||
static constexpr int y = A<1>::B<J>::y;
|
||||
};
|
||||
|
||||
template<>
|
||||
template<int J>
|
||||
struct A<1>::B {
|
||||
static constexpr int y = J;
|
||||
};
|
||||
|
||||
static_assert(A<0>::f<2>() == 2);
|
||||
static_assert(A<0>::x<2> == 2);
|
||||
static_assert(A<0>::B<2>::y == 2);
|
||||
} // namespace Dependent
|
@ -199,9 +199,7 @@ namespace hidden_specializations {
|
||||
cls<char*> uk4; // expected-error 1+{{partial specialization of 'cls<T *>' must be imported}} expected-error 1+{{definition of}}
|
||||
cls<void>::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}}
|
||||
cls<void>::nested_cls_t<int> unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
|
||||
// expected-error@cxx-templates-unimported.h:29 {{explicit specialization of 'nested_cls_t' must be imported}}
|
||||
// expected-note@-2 {{in evaluation of exception specification}}
|
||||
cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}}
|
||||
cls<void>::nested_cls_t<char> unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}}
|
||||
|
||||
// For enums, uses that would trigger instantiations of definitions are not
|
||||
// allowed.
|
||||
|
Loading…
x
Reference in New Issue
Block a user