Reland: [clang] fix P3310 overload resolution flag propagation (#125791)

Class templates might be only instantiated when they are required to be
complete, but checking the template args against the primary template is
immediate.

This result is cached so that later when the class is instantiated,
checking against the primary template is not repeated.

The 'MatchedPackOnParmToNonPackOnArg' flag is also produced upon
checking against the primary template, so it needs to be cached in the
specialziation as well.

This fixes a bug which has not been in any release, so there are no
release notes.

Fixes #125290
This commit is contained in:
Matheus Izvekov 2025-02-05 12:02:24 -03:00 committed by GitHub
parent e151b1d1f6
commit 08bda1cc6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 6143 additions and 45 deletions

View File

@ -1841,15 +1841,23 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
LLVM_PREFERRED_TYPE(TemplateSpecializationKind)
unsigned SpecializationKind : 3;
/// Indicate that we have matched a parameter pack with a non pack
/// argument, when the opposite match is also allowed (strict pack match).
/// This needs to be cached as deduction is performed during declaration,
/// and we need the information to be preserved so that it is consistent
/// during instantiation.
bool MatchedPackOnParmToNonPackOnArg : 1;
protected:
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
bool MatchedPackOnParmToNonPackOnArg,
ClassTemplateSpecializationDecl *PrevDecl);
explicit ClassTemplateSpecializationDecl(ASTContext &C, Kind DK);
ClassTemplateSpecializationDecl(ASTContext &C, Kind DK);
public:
friend class ASTDeclReader;
@ -1859,7 +1867,7 @@ public:
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
ArrayRef<TemplateArgument> Args, bool MatchedPackOnParmToNonPackOnArg,
ClassTemplateSpecializationDecl *PrevDecl);
static ClassTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
@ -1930,6 +1938,10 @@ public:
SpecializationKind = TSK;
}
bool hasMatchedPackOnParmToNonPackOnArg() const {
return MatchedPackOnParmToNonPackOnArg;
}
/// Get the point of instantiation (if any), or null if none.
SourceLocation getPointOfInstantiation() const {
return PointOfInstantiation;

View File

@ -13499,8 +13499,8 @@ public:
bool InstantiateClassTemplateSpecialization(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
TemplateSpecializationKind TSK, bool Complain = true,
bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false);
TemplateSpecializationKind TSK, bool Complain,
bool PrimaryHasMatchedPackOnParmToNonPackOnArg);
/// Instantiates the definitions of all of the member
/// of the given class, which is an instantiation of a class template

View File

@ -6321,9 +6321,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
updateLookupTableForTemplateParameters(*ToTPList);
} else { // Not a partial specialization.
if (GetImportedOrCreateDecl(
D2, D, Importer.getToContext(), D->getTagKind(), DC,
*BeginLocOrErr, *IdLocOrErr, ClassTemplate, TemplateArgs,
PrevDecl))
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
*IdLocOrErr, ClassTemplate, TemplateArgs,
D->hasMatchedPackOnParmToNonPackOnArg(), PrevDecl))
return D2;
// Update InsertPos, because preceding import calls may have invalidated

View File

@ -957,18 +957,20 @@ FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create(
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
ClassTemplateSpecializationDecl *PrevDecl)
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(
ASTContext &Context, Kind DK, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
bool MatchedPackOnParmToNonPackOnArg,
ClassTemplateSpecializationDecl *PrevDecl)
: CXXRecordDecl(DK, TK, Context, DC, StartLoc, IdLoc,
SpecializedTemplate->getIdentifier(), PrevDecl),
SpecializedTemplate(SpecializedTemplate),
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)),
SpecializationKind(TSK_Undeclared) {
SpecializedTemplate(SpecializedTemplate),
TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args)),
SpecializationKind(TSK_Undeclared),
MatchedPackOnParmToNonPackOnArg(MatchedPackOnParmToNonPackOnArg) {
assert(DK == Kind::ClassTemplateSpecialization ||
MatchedPackOnParmToNonPackOnArg == false);
}
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(ASTContext &C,
@ -977,18 +979,14 @@ ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(ASTContext &C,
SourceLocation(), nullptr, nullptr),
SpecializationKind(TSK_Undeclared) {}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
ClassTemplateSpecializationDecl *PrevDecl) {
auto *Result =
new (Context, DC) ClassTemplateSpecializationDecl(
Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, PrevDecl);
ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args, bool MatchedPackOnParmToNonPackOnArg,
ClassTemplateSpecializationDecl *PrevDecl) {
auto *Result = new (Context, DC) ClassTemplateSpecializationDecl(
Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, MatchedPackOnParmToNonPackOnArg, PrevDecl);
Result->setMayHaveOutOfDateDef(false);
// If the template decl is incomplete, copy the external lexical storage from
@ -1175,7 +1173,10 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(
Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, PrevDecl),
// Tracking MatchedPackOnParmToNonPackOnArg for Partial
// Specializations is not needed.
SpecializedTemplate, Args, /*MatchedPackOnParmToNonPackOnArg=*/false,
PrevDecl),
TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
if (AdoptTemplateParameterList(Params, this))
setInvalidDecl();

View File

@ -1003,6 +1003,11 @@ void JSONNodeDumper::VisitRecordDecl(const RecordDecl *RD) {
void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
VisitRecordDecl(RD);
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
if (CTSD->hasMatchedPackOnParmToNonPackOnArg())
JOS.attribute("strict-pack-match", true);
}
// All other information requires a complete definition.
if (!RD->isCompleteDefinition())
return;

View File

@ -2525,8 +2525,11 @@ void TextNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
OS << " instantiated_from";
dumpPointer(Instance);
}
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D))
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
dumpTemplateSpecializationKind(CTSD->getSpecializationKind());
if (CTSD->hasMatchedPackOnParmToNonPackOnArg())
OS << " strict-pack-match";
}
dumpNestedNameSpecifier(D->getQualifier());

View File

@ -3651,7 +3651,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getDeclContext(),
ClassTemplate->getTemplatedDecl()->getBeginLoc(),
ClassTemplate->getLocation(), ClassTemplate, CTAI.CanonicalConverted,
nullptr);
CTAI.MatchedPackOnParmToNonPackOnArg, nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@ -8526,7 +8526,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
// this explicit specialization or friend declaration.
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, DC, KWLoc, TemplateNameLoc, ClassTemplate,
CTAI.CanonicalConverted, PrevDecl);
CTAI.CanonicalConverted, CTAI.MatchedPackOnParmToNonPackOnArg,
PrevDecl);
Specialization->setTemplateArgsAsWritten(TemplateArgs);
SetNestedNameSpecifier(*this, Specialization, SS);
if (TemplateParameterLists.size() > 0) {
@ -9869,7 +9870,8 @@ DeclResult Sema::ActOnExplicitInstantiation(
// this explicit specialization.
Specialization = ClassTemplateSpecializationDecl::Create(
Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc,
ClassTemplate, CTAI.CanonicalConverted, PrevDecl);
ClassTemplate, CTAI.CanonicalConverted,
CTAI.MatchedPackOnParmToNonPackOnArg, PrevDecl);
SetNestedNameSpecifier(*this, Specialization, SS);
// A MSInheritanceAttr attached to the previous declaration must be

View File

@ -3341,8 +3341,6 @@ FinishTemplateArgumentDeduction(
return ConstraintsNotSatisfied
? TemplateDeductionResult::ConstraintsNotSatisfied
: TemplateDeductionResult::SubstitutionFailure;
if (InstCTAI.MatchedPackOnParmToNonPackOnArg)
Info.setMatchedPackOnParmToNonPackOnArg();
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {

View File

@ -4038,7 +4038,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl::Create(
SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(),
D->getLocation(), InstClassTemplate, CTAI.CanonicalConverted,
PrevDecl);
CTAI.MatchedPackOnParmToNonPackOnArg, PrevDecl);
InstD->setTemplateArgsAsWritten(InstTemplateArgs);
// Add this partial specialization to the set of class template partial

View File

@ -9399,7 +9399,8 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
runWithSufficientStackSpace(Loc, [&] {
Diagnosed = InstantiateClassTemplateSpecialization(
Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
/*Complain=*/Diagnoser,
ClassTemplateSpec->hasMatchedPackOnParmToNonPackOnArg());
});
Instantiated = true;
}

View File

@ -2532,6 +2532,7 @@ RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
D->PointOfInstantiation = readSourceLocation();
D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
D->MatchedPackOnParmToNonPackOnArg = Record.readBool();
bool writtenAsCanonicalDecl = Record.readInt();
if (writtenAsCanonicalDecl) {

View File

@ -1843,6 +1843,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
Record.AddTemplateArgumentList(&D->getTemplateArgs());
Record.AddSourceLocation(D->getPointOfInstantiation());
Record.push_back(D->getSpecializationKind());
Record.push_back(D->hasMatchedPackOnParmToNonPackOnArg());
Record.push_back(D->isCanonicalDecl());
if (D->isCanonicalDecl()) {

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,12 @@ def main():
action="store",
default="",
)
parser.add_argument(
"--prefix",
help="The FileCheck prefix",
action="store",
default="CHECK",
)
update_or_generate_group = parser.add_mutually_exclusive_group()
update_or_generate_group.add_argument(
"--update", help="Update the file in-place", action="store_true"
@ -113,11 +119,18 @@ def main():
cmdline_opts=args.opts,
do_update=args.update,
force_update=args.update_manual,
prefix=args.prefix,
)
def process_file(
source_file, clang_binary, cmdline_filters, cmdline_opts, do_update, force_update
source_file,
clang_binary,
cmdline_filters,
cmdline_opts,
do_update,
force_update,
prefix,
):
note_firstline = (
"// NOTE: CHECK lines have been autogenerated by " "gen_ast_dump_json_test.py"
@ -227,14 +240,14 @@ def process_file(
for out_ast in out_asts:
append_str = json.dumps(out_ast, indent=1, ensure_ascii=False)
out_str = "\n\n"
out_str += "// CHECK-NOT: {{^}}Dumping\n"
out_str += f"// {prefix}-NOT: {{{{^}}}}Dumping\n"
index = 0
for append_line in append_str.splitlines()[2:]:
if index == 0:
out_str += "// CHECK: %s\n" % (append_line.rstrip())
out_str += f"// {prefix}: %s\n" % (append_line.rstrip())
index += 1
else:
out_str += "// CHECK-NEXT: %s\n" % (append_line.rstrip())
out_str += f"// {prefix}-NEXT: %s\n" % (append_line.rstrip())
f.write(out_str)
f.flush()

View File

@ -585,6 +585,23 @@ namespace regression2 {
template <typename, int> struct Matrix;
template struct D<Matrix<double, 3>>;
} // namespace regression2
namespace regression3 {
struct None {};
template<class T> struct Node { using type = T; };
template <template<class> class TT, class T>
struct A {
static_assert(!__is_same(T, None));
using type2 = typename A<TT, typename T::type>::type2;
};
template <template<class> class TT> struct A<TT, None> {
using type2 = void;
};
template <class...> class B {};
template struct A<B, Node<None>>;
} // namespace regression3
namespace nttp_auto {
namespace t1 {

View File

@ -280,7 +280,8 @@ std::optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) {
new_class_template->getDeclContext(),
new_class_template->getTemplatedDecl()->getLocation(),
new_class_template->getLocation(), new_class_template, imported_args,
nullptr);
td->hasMatchedPackOnParmToNonPackOnArg(),
/*PrevDecl=*/nullptr);
new_class_template->AddSpecialization(result, InsertPos);
if (new_class_template->isOutOfLine())