Skip to content

[clang] remove unneeded template deduction canonicalizations #101594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4202,7 +4202,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
TemplateDeductionInfo Info(FailedCandidates.getLocation());

if (TemplateDeductionResult Result =
DeduceTemplateArguments(Partial, CanonicalConverted, Info);
DeduceTemplateArguments(Partial, SugaredConverted, Info);
Result != TemplateDeductionResult::Success) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
Expand All @@ -4213,7 +4213,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
} else {
Matched.push_back(PartialSpecMatchResult());
Matched.back().Partial = Partial;
Matched.back().Args = Info.takeCanonical();
Matched.back().Args = Info.takeSugared();
}
}

Expand Down
87 changes: 32 additions & 55 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,6 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T,
TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
TemplateArgument New(D, T);
return DeduceNonTypeTemplateArgument(
S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced);
Expand Down Expand Up @@ -1380,11 +1379,6 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
return false;
}

static CXXRecordDecl *getCanonicalRD(QualType T) {
return cast<CXXRecordDecl>(
T->castAs<RecordType>()->getDecl()->getCanonicalDecl());
}

/// Attempt to deduce the template arguments by checking the base types
/// according to (C++20 [temp.deduct.call] p4b3.
///
Expand Down Expand Up @@ -1439,7 +1433,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
for (const auto &Base : RD->bases()) {
QualType T = Base.getType();
assert(T->isRecordType() && "Base class that isn't a record?");
if (Visited.insert(::getCanonicalRD(T)).second)
if (Visited.insert(T->getAsCXXRecordDecl()).second)
ToVisit.push_back(T);
}
};
Expand All @@ -1460,7 +1454,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,

// If this was a successful deduction, add it to the list of matches,
// otherwise we need to continue searching its bases.
const CXXRecordDecl *RD = ::getCanonicalRD(NextT);
const CXXRecordDecl *RD = NextT->getAsCXXRecordDecl();
if (BaseResult == TemplateDeductionResult::Success)
Matches.insert({RD, DeducedCopy});
else
Expand All @@ -1481,7 +1475,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
// We can give up once we have a single item (or have run out of things to
// search) since cyclical inheritance isn't valid.
while (Matches.size() > 1 && !ToVisit.empty()) {
const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val());
const CXXRecordDecl *RD = ToVisit.pop_back_val()->getAsCXXRecordDecl();
Matches.erase(RD);

// Always add all bases, since the inheritance tree can contain
Expand Down Expand Up @@ -2030,15 +2024,16 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (!S.isCompleteType(Info.getLocation(), A))
return Result;

if (getCanonicalRD(A)->isInvalidDecl())
const CXXRecordDecl *RD = A->getAsCXXRecordDecl();
if (RD->isInvalidDecl())
return Result;

// Reset the incorrectly deduced argument from above.
Deduced = DeducedOrig;

// Check bases according to C++14 [temp.deduct.call] p4b3:
auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A),
TemplateParams, P, Info, Deduced);
auto BaseResult =
DeduceTemplateBases(S, RD, TemplateParams, P, Info, Deduced);
return BaseResult != TemplateDeductionResult::Invalid ? BaseResult
: Result;
}
Expand Down Expand Up @@ -3369,9 +3364,7 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType,
// Use the InjectedClassNameType.
PType = Context.getTypeDeclType(CTD->getTemplatedDecl());
} else if (const auto *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(TD)) {
PType = AliasTemplate->getTemplatedDecl()
->getUnderlyingType()
.getCanonicalType();
PType = AliasTemplate->getTemplatedDecl()->getUnderlyingType();
} else {
assert(false && "Expected a class or alias template");
}
Expand Down Expand Up @@ -3505,15 +3498,15 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
// the explicit template arguments. They'll be used as part of deduction
// for this template parameter pack.
unsigned PartiallySubstitutedPackIndex = -1u;
if (!CanonicalBuilder.empty()) {
const TemplateArgument &Arg = CanonicalBuilder.back();
if (!SugaredBuilder.empty()) {
const TemplateArgument &Arg = SugaredBuilder.back();
if (Arg.getKind() == TemplateArgument::Pack) {
auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1);
auto *Param = TemplateParams->getParam(SugaredBuilder.size() - 1);
// If this is a fully-saturated fixed-size pack, it should be
// fully-substituted, not partially-substituted.
std::optional<unsigned> Expansions = getExpandedPackSize(Param);
if (!Expansions || Arg.pack_size() < *Expansions) {
PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1;
PartiallySubstitutedPackIndex = SugaredBuilder.size() - 1;
CurrentInstantiationScope->SetPartiallySubstitutedPack(
Param, Arg.pack_begin(), Arg.pack_size());
}
Expand Down Expand Up @@ -3890,8 +3883,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
if (!Specialization || Specialization->isInvalidDecl())
return TemplateDeductionResult::SubstitutionFailure;

assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
FunctionTemplate->getCanonicalDecl());
assert(isSameDeclaration(Specialization->getPrimaryTemplate(),
FunctionTemplate));

// If the template argument list is owned by the function template
// specialization, release it.
Expand Down Expand Up @@ -4736,8 +4729,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// types, template argument deduction fails.
if (!ArgFunctionType.isNull()) {
if (IsAddressOfFunction ? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
SpecializationType, ArgFunctionType)
: !Context.hasSameFunctionTypeIgnoringExceptionSpec(
SpecializationType, ArgFunctionType)) {
Info.FirstArg = TemplateArgument(SpecializationType);
Expand All @@ -4751,19 +4743,17 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(

TemplateDeductionResult Sema::DeduceTemplateArguments(
FunctionTemplateDecl *ConversionTemplate, QualType ObjectType,
Expr::Classification ObjectClassification, QualType ToType,
Expr::Classification ObjectClassification, QualType A,
CXXConversionDecl *&Specialization, TemplateDeductionInfo &Info) {
if (ConversionTemplate->isInvalidDecl())
return TemplateDeductionResult::Invalid;

CXXConversionDecl *ConversionGeneric
= cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());

QualType FromType = ConversionGeneric->getConversionType();

// Canonicalize the types for deduction.
QualType P = Context.getCanonicalType(FromType);
QualType A = Context.getCanonicalType(ToType);
QualType P = ConversionGeneric->getConversionType();
bool IsReferenceP = P->isReferenceType();
bool IsReferenceA = A->isReferenceType();

// C++0x [temp.deduct.conv]p2:
// If P is a reference type, the type referred to by P is used for
Expand All @@ -4779,7 +4769,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// We work around a defect in the standard here: cv-qualifiers are also
// removed from P and A in this case, unless P was a reference type. This
// seems to mostly match what other compilers are doing.
if (!FromType->getAs<ReferenceType>()) {
if (!IsReferenceP) {
A = A.getUnqualifiedType();
P = P.getUnqualifiedType();
}
Expand Down Expand Up @@ -4835,7 +4825,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// - If the original A is a reference type, A can be more
// cv-qualified than the deduced A (i.e., the type referred to
// by the reference)
if (ToType->isReferenceType())
if (IsReferenceA)
TDF |= TDF_ArgWithReferenceType;
// - The deduced A can be another pointer or pointer to member
// type that can be converted to A via a qualification
Expand Down Expand Up @@ -5736,17 +5726,6 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
return AtLeastAsConstrained1 ? FT1 : FT2;
}

/// Determine if the two templates are equivalent.
static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
if (T1 == T2)
return true;

if (!T1 || !T2)
return false;

return T1->getCanonicalDecl() == T2->getCanonicalDecl();
}

UnresolvedSetIterator Sema::getMostSpecialized(
UnresolvedSetIterator SpecBegin, UnresolvedSetIterator SpecEnd,
TemplateSpecCandidateSet &FailedCandidates,
Expand Down Expand Up @@ -5774,9 +5753,9 @@ UnresolvedSetIterator Sema::getMostSpecialized(
FunctionTemplateDecl *Challenger
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
assert(Challenger && "Not a function template specialization?");
if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, Loc,
TPOC_Other, 0),
Challenger)) {
if (declaresSameEntity(getMoreSpecializedTemplate(BestTemplate, Challenger,
Loc, TPOC_Other, 0),
Challenger)) {
Best = I;
BestTemplate = Challenger;
}
Expand All @@ -5789,9 +5768,9 @@ UnresolvedSetIterator Sema::getMostSpecialized(
FunctionTemplateDecl *Challenger
= cast<FunctionDecl>(*I)->getPrimaryTemplate();
if (I != Best &&
!isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
Loc, TPOC_Other, 0),
BestTemplate)) {
!declaresSameEntity(getMoreSpecializedTemplate(BestTemplate, Challenger,
Loc, TPOC_Other, 0),
BestTemplate)) {
Ambiguous = true;
break;
}
Expand Down Expand Up @@ -6116,11 +6095,10 @@ Sema::getMoreSpecializedPartialSpecialization(
"the partial specializations being compared should specialize"
" the same template.");
TemplateName Name(PS1->getSpecializedTemplate());
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
QualType PT1 = Context.getTemplateSpecializationType(
CanonTemplate, PS1->getTemplateArgs().asArray());
Name, PS1->getTemplateArgs().asArray());
QualType PT2 = Context.getTemplateSpecializationType(
CanonTemplate, PS2->getTemplateArgs().asArray());
Name, PS2->getTemplateArgs().asArray());

TemplateDeductionInfo Info(Loc);
return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
Expand All @@ -6129,12 +6107,11 @@ Sema::getMoreSpecializedPartialSpecialization(
bool Sema::isMoreSpecializedThanPrimary(
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
TemplateName CanonTemplate =
Context.getCanonicalTemplateName(TemplateName(Primary));
TemplateName Name(Primary);
QualType PrimaryT = Context.getTemplateSpecializationType(
CanonTemplate, Primary->getInjectedTemplateArgs());
Name, Primary->getInjectedTemplateArgs());
QualType PartialT = Context.getTemplateSpecializationType(
CanonTemplate, Spec->getTemplateArgs().asArray());
Name, Spec->getTemplateArgs().asArray());

VarTemplatePartialSpecializationDecl *MaybeSpec =
getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
Expand Down
8 changes: 4 additions & 4 deletions clang/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct X { };
struct Y { };
struct Z { };

int test() {
int test() {
{
auto L = [](auto ... as) { };
L.operator()<bool>(true);
Expand All @@ -36,7 +36,7 @@ int test() {
{
auto L = [](auto a, auto b, auto ... cs) { };
L.operator()<bool, char>(false, 'a');
L.operator()<bool, char, const char*>(false, 'a', "jim");
L.operator()<bool, char, const char*>(false, 'a', "jim");
}

{
Expand Down Expand Up @@ -77,7 +77,7 @@ int test() {
M(6.26, "jim", true);
M.operator()<X>(6.26, "jim", false, X{}, Y{}, Z{});
}

return 0;
}
int run = test();
Expand Down Expand Up @@ -106,7 +106,7 @@ namespace PR33082 {
template<int ...I> void a() {
int arr[] = { [](auto ...K) { (void)I; } ... };
// expected-error@-1 {{no viable conversion}}
// expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(type-parameter-0-0...){{.*}}' against 'int'}}
// expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(auto...){{.*}}' against 'int'}}
}

template<typename ...T> struct Pack {};
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ namespace conversion_operator {
int (&fp2)(int) = [](auto a) { return a; }; // expected-error{{non-const lvalue}}
int (&&fp3)(int) = [](auto a) { return a; };
// expected-error@-1 {{no viable conversion}}
// expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(type-parameter-0-0){{.*}}' against 'int (int)'}}
// expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(auto){{.*}}' against 'int (int)'}}

using F = int(int);
using G = int(void*);
Expand Down Expand Up @@ -293,7 +293,7 @@ int test() {
print("a = ", a, "\n");
return [](auto b) ->decltype(a) {
// expected-error@-1 {{no viable conversion}}
// expected-note-re@-2 {{candidate template ignored: could not match 'int (*)(type-parameter-0-0){{.*}}' against 'int'}}
// expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(auto){{.*}}' ({{.*}}) against 'decltype(a)' (aka 'int')}}
print("b = ", b, "\n");
return b;
};
Expand Down
Loading