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:
parent
e151b1d1f6
commit
08bda1cc6b
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
|
Loading…
x
Reference in New Issue
Block a user