@@ -5333,38 +5333,38 @@ bool Sema::CheckIfFunctionSpecializationIsImmediate(FunctionDecl *FD,
5333
5333
return false ;
5334
5334
}
5335
5335
5336
- // / If this is a non-static member function,
5337
- static void
5338
- AddImplicitObjectParameterType (ASTContext &Context,
5339
- CXXMethodDecl *Method,
5340
- SmallVectorImpl<QualType> &ArgTypes) {
5341
- // C++11 [temp.func.order]p3:
5342
- // [...] The new parameter is of type "reference to cv A," where cv are
5343
- // the cv-qualifiers of the function template (if any) and A is
5344
- // the class of which the function template is a member.
5336
+ static QualType GetImplicitObjectParameterType (ASTContext &Context,
5337
+ const CXXMethodDecl *Method,
5338
+ QualType RawType,
5339
+ bool IsOtherRvr) {
5340
+ // C++20 [temp.func.order]p3.1, p3.2:
5341
+ // - The type X(M) is "rvalue reference to cv A" if the optional
5342
+ // ref-qualifier of M is && or if M has no ref-qualifier and the
5343
+ // positionally-corresponding parameter of the other transformed template
5344
+ // has rvalue reference type; if this determination depends recursively
5345
+ // upon whether X(M) is an rvalue reference type, it is not considered to
5346
+ // have rvalue reference type.
5345
5347
//
5346
- // The standard doesn't say explicitly, but we pick the appropriate kind of
5347
- // reference type based on [over.match.funcs]p4.
5348
- assert (Method && Method->isImplicitObjectMemberFunction () &&
5349
- " expected an implicit objet function" );
5350
- QualType ArgTy = Context.getTypeDeclType (Method->getParent ());
5351
- ArgTy = Context.getQualifiedType (ArgTy, Method->getMethodQualifiers ());
5352
- if (Method->getRefQualifier () == RQ_RValue)
5353
- ArgTy = Context.getRValueReferenceType (ArgTy);
5354
- else
5355
- ArgTy = Context.getLValueReferenceType (ArgTy);
5356
- ArgTypes.push_back (ArgTy);
5348
+ // - Otherwise, X(M) is "lvalue reference to cv A".
5349
+ assert (Method && !Method->isExplicitObjectMemberFunction () &&
5350
+ " expected a member function with no explicit object parameter" );
5351
+
5352
+ RawType = Context.getQualifiedType (RawType, Method->getMethodQualifiers ());
5353
+ if (Method->getRefQualifier () == RQ_RValue ||
5354
+ (IsOtherRvr && Method->getRefQualifier () == RQ_None))
5355
+ return Context.getRValueReferenceType (RawType);
5356
+ return Context.getLValueReferenceType (RawType);
5357
5357
}
5358
5358
5359
5359
// / Determine whether the function template \p FT1 is at least as
5360
5360
// / specialized as \p FT2.
5361
- static bool isAtLeastAsSpecializedAs (Sema &S,
5362
- SourceLocation Loc,
5363
- FunctionTemplateDecl *FT1,
5364
- FunctionTemplateDecl *FT2,
5361
+ static bool isAtLeastAsSpecializedAs (Sema &S, SourceLocation Loc,
5362
+ const FunctionTemplateDecl *FT1,
5363
+ const FunctionTemplateDecl *FT2,
5365
5364
TemplatePartialOrderingContext TPOC,
5366
- unsigned NumCallArguments1,
5367
- bool Reversed) {
5365
+ bool Reversed,
5366
+ const SmallVector<QualType> &Args1,
5367
+ const SmallVector<QualType> &Args2) {
5368
5368
assert (!Reversed || TPOC == TPOC_Call);
5369
5369
5370
5370
FunctionDecl *FD1 = FT1->getTemplatedDecl ();
@@ -5381,74 +5381,15 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
5381
5381
// The types used to determine the ordering depend on the context in which
5382
5382
// the partial ordering is done:
5383
5383
TemplateDeductionInfo Info (Loc);
5384
- SmallVector<QualType, 4 > Args2;
5385
5384
switch (TPOC) {
5386
- case TPOC_Call: {
5387
- // - In the context of a function call, the function parameter types are
5388
- // used.
5389
- CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
5390
- CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
5391
-
5392
- // C++11 [temp.func.order]p3:
5393
- // [...] If only one of the function templates is a non-static
5394
- // member, that function template is considered to have a new
5395
- // first parameter inserted in its function parameter list. The
5396
- // new parameter is of type "reference to cv A," where cv are
5397
- // the cv-qualifiers of the function template (if any) and A is
5398
- // the class of which the function template is a member.
5399
- //
5400
- // Note that we interpret this to mean "if one of the function
5401
- // templates is a non-static member and the other is a non-member";
5402
- // otherwise, the ordering rules for static functions against non-static
5403
- // functions don't make any sense.
5404
- //
5405
- // C++98/03 doesn't have this provision but we've extended DR532 to cover
5406
- // it as wording was broken prior to it.
5407
- SmallVector<QualType, 4 > Args1;
5408
-
5409
- unsigned NumComparedArguments = NumCallArguments1;
5410
-
5411
- if (!Method2 && Method1 && Method1->isImplicitObjectMemberFunction ()) {
5412
- // Compare 'this' from Method1 against first parameter from Method2.
5413
- AddImplicitObjectParameterType (S.Context , Method1, Args1);
5414
- ++NumComparedArguments;
5415
- } else if (!Method1 && Method2 &&
5416
- Method2->isImplicitObjectMemberFunction ()) {
5417
- // Compare 'this' from Method2 against first parameter from Method1.
5418
- AddImplicitObjectParameterType (S.Context , Method2, Args2);
5419
- } else if (Method1 && Method2 && Reversed &&
5420
- Method1->isImplicitObjectMemberFunction () &&
5421
- Method2->isImplicitObjectMemberFunction ()) {
5422
- // Compare 'this' from Method1 against second parameter from Method2
5423
- // and 'this' from Method2 against second parameter from Method1.
5424
- AddImplicitObjectParameterType (S.Context , Method1, Args1);
5425
- AddImplicitObjectParameterType (S.Context , Method2, Args2);
5426
- ++NumComparedArguments;
5427
- }
5428
-
5429
- Args1.insert (Args1.end (), Proto1->param_type_begin (),
5430
- Proto1->param_type_end ());
5431
- Args2.insert (Args2.end (), Proto2->param_type_begin (),
5432
- Proto2->param_type_end ());
5433
-
5434
- // C++ [temp.func.order]p5:
5435
- // The presence of unused ellipsis and default arguments has no effect on
5436
- // the partial ordering of function templates.
5437
- if (Args1.size () > NumComparedArguments)
5438
- Args1.resize (NumComparedArguments);
5439
- if (Args2.size () > NumComparedArguments)
5440
- Args2.resize (NumComparedArguments);
5441
- if (Reversed)
5442
- std::reverse (Args2.begin (), Args2.end ());
5443
-
5385
+ case TPOC_Call:
5444
5386
if (DeduceTemplateArguments (S, TemplateParams, Args2.data (), Args2.size (),
5445
5387
Args1.data (), Args1.size (), Info, Deduced,
5446
5388
TDF_None, /* PartialOrdering=*/ true ) !=
5447
5389
TemplateDeductionResult::Success)
5448
5390
return false ;
5449
5391
5450
5392
break ;
5451
- }
5452
5393
5453
5394
case TPOC_Conversion:
5454
5395
// - In the context of a call to a conversion operator, the return types
@@ -5536,8 +5477,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
5536
5477
// / \param NumCallArguments1 The number of arguments in the call to FT1, used
5537
5478
// / only when \c TPOC is \c TPOC_Call.
5538
5479
// /
5539
- // / \param NumCallArguments2 The number of arguments in the call to FT2, used
5540
- // / only when \c TPOC is \c TPOC_Call.
5480
+ // / \param RawObj1Ty The type of the object parameter of FT1 if a member
5481
+ // / function only used if \c TPOC is \c TPOC_Call and FT1 is a Function
5482
+ // / template from a member function
5483
+ // /
5484
+ // / \param RawObj2Ty The type of the object parameter of FT2 if a member
5485
+ // / function only used if \c TPOC is \c TPOC_Call and FT2 is a Function
5486
+ // / template from a member function
5541
5487
// /
5542
5488
// / \param Reversed If \c true, exactly one of FT1 and FT2 is an overload
5543
5489
// / candidate with a reversed parameter order. In this case, the corresponding
@@ -5548,13 +5494,76 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
5548
5494
FunctionTemplateDecl *Sema::getMoreSpecializedTemplate (
5549
5495
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
5550
5496
TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
5551
- unsigned NumCallArguments2, bool Reversed) {
5497
+ QualType RawObj1Ty, QualType RawObj2Ty, bool Reversed) {
5498
+ SmallVector<QualType> Args1;
5499
+ SmallVector<QualType> Args2;
5500
+ const FunctionDecl *FD1 = FT1->getTemplatedDecl ();
5501
+ const FunctionDecl *FD2 = FT2->getTemplatedDecl ();
5502
+ bool ShouldConvert1 = false ;
5503
+ bool ShouldConvert2 = false ;
5504
+ QualType Obj1Ty;
5505
+ QualType Obj2Ty;
5506
+ if (TPOC == TPOC_Call) {
5507
+ const FunctionProtoType *Proto1 =
5508
+ FD1->getType ()->getAs <FunctionProtoType>();
5509
+ const FunctionProtoType *Proto2 =
5510
+ FD2->getType ()->getAs <FunctionProtoType>();
5511
+
5512
+ // - In the context of a function call, the function parameter types are
5513
+ // used.
5514
+ const CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
5515
+ const CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
5516
+ // C++20 [temp.func.order]p3
5517
+ // [...] Each function template M that is a member function is
5518
+ // considered to have a new first parameter of type
5519
+ // X(M), described below, inserted in its function parameter list.
5520
+ //
5521
+ // Note that we interpret "that is a member function" as
5522
+ // "that is a member function with no expicit object argument".
5523
+ // Otherwise the ordering rules for methods with expicit objet arguments
5524
+ // against anything else make no sense.
5525
+ ShouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction ();
5526
+ ShouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction ();
5527
+ if (ShouldConvert1) {
5528
+ bool IsRValRef2 =
5529
+ ShouldConvert2
5530
+ ? Method2->getRefQualifier () == RQ_RValue
5531
+ : Proto2->param_type_begin ()[0 ]->isRValueReferenceType ();
5532
+ // Compare 'this' from Method1 against first parameter from Method2.
5533
+ Obj1Ty = GetImplicitObjectParameterType (this ->Context , Method1, RawObj1Ty,
5534
+ IsRValRef2);
5535
+ Args1.push_back (Obj1Ty);
5536
+ }
5537
+ if (ShouldConvert2) {
5538
+ bool IsRValRef1 =
5539
+ ShouldConvert1
5540
+ ? Method1->getRefQualifier () == RQ_RValue
5541
+ : Proto1->param_type_begin ()[0 ]->isRValueReferenceType ();
5542
+ // Compare 'this' from Method2 against first parameter from Method1.
5543
+ Obj2Ty = GetImplicitObjectParameterType (this ->Context , Method2, RawObj2Ty,
5544
+ IsRValRef1);
5545
+ Args2.push_back (Obj2Ty);
5546
+ }
5547
+ size_t NumComparedArguments = NumCallArguments1 + ShouldConvert1;
5548
+
5549
+ Args1.insert (Args1.end (), Proto1->param_type_begin (),
5550
+ Proto1->param_type_end ());
5551
+ Args2.insert (Args2.end (), Proto2->param_type_begin (),
5552
+ Proto2->param_type_end ());
5552
5553
5553
- bool Better1 = isAtLeastAsSpecializedAs (*this , Loc, FT1, FT2, TPOC,
5554
- NumCallArguments1, Reversed);
5555
- bool Better2 = isAtLeastAsSpecializedAs (*this , Loc, FT2, FT1, TPOC,
5556
- NumCallArguments2, Reversed);
5554
+ // C++ [temp.func.order]p5:
5555
+ // The presence of unused ellipsis and default arguments has no effect on
5556
+ // the partial ordering of function templates.
5557
+ Args1.resize (std::min (Args1.size (), NumComparedArguments));
5558
+ Args2.resize (std::min (Args2.size (), NumComparedArguments));
5557
5559
5560
+ if (Reversed)
5561
+ std::reverse (Args2.begin (), Args2.end ());
5562
+ }
5563
+ bool Better1 = isAtLeastAsSpecializedAs (*this , Loc, FT1, FT2, TPOC, Reversed,
5564
+ Args1, Args2);
5565
+ bool Better2 = isAtLeastAsSpecializedAs (*this , Loc, FT2, FT1, TPOC, Reversed,
5566
+ Args2, Args1);
5558
5567
// C++ [temp.deduct.partial]p10:
5559
5568
// F is more specialized than G if F is at least as specialized as G and G
5560
5569
// is not at least as specialized as F.
@@ -5568,12 +5577,28 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
5568
5577
// ... and if G has a trailing function parameter pack for which F does not
5569
5578
// have a corresponding parameter, and if F does not have a trailing
5570
5579
// function parameter pack, then F is more specialized than G.
5571
- FunctionDecl *FD1 = FT1->getTemplatedDecl ();
5572
- FunctionDecl *FD2 = FT2->getTemplatedDecl ();
5573
- unsigned NumParams1 = FD1->getNumParams ();
5574
- unsigned NumParams2 = FD2->getNumParams ();
5575
- bool Variadic1 = NumParams1 && FD1->parameters ().back ()->isParameterPack ();
5576
- bool Variadic2 = NumParams2 && FD2->parameters ().back ()->isParameterPack ();
5580
+
5581
+ SmallVector<QualType> Param1;
5582
+ Param1.reserve (FD1->param_size () + ShouldConvert1);
5583
+ if (ShouldConvert1)
5584
+ Param1.push_back (Obj1Ty);
5585
+ for (const auto &P : FD1->parameters ())
5586
+ Param1.push_back (P->getType ());
5587
+
5588
+ SmallVector<QualType> Param2;
5589
+ Param2.reserve (FD2->param_size () + ShouldConvert2);
5590
+ if (ShouldConvert2)
5591
+ Param2.push_back (Obj2Ty);
5592
+ for (const auto &P : FD2->parameters ())
5593
+ Param2.push_back (P->getType ());
5594
+
5595
+ unsigned NumParams1 = Param1.size ();
5596
+ unsigned NumParams2 = Param2.size ();
5597
+
5598
+ bool Variadic1 =
5599
+ FD1->param_size () && FD1->parameters ().back ()->isParameterPack ();
5600
+ bool Variadic2 =
5601
+ FD2->param_size () && FD2->parameters ().back ()->isParameterPack ();
5577
5602
if (Variadic1 != Variadic2) {
5578
5603
if (Variadic1 && NumParams1 > NumParams2)
5579
5604
return FT2;
@@ -5584,8 +5609,8 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
5584
5609
// This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
5585
5610
// there is no wording or even resolution for this issue.
5586
5611
for (int i = 0 , e = std::min (NumParams1, NumParams2); i < e; ++i) {
5587
- QualType T1 = FD1-> getParamDecl (i)-> getType () .getCanonicalType ();
5588
- QualType T2 = FD2-> getParamDecl (i)-> getType () .getCanonicalType ();
5612
+ QualType T1 = Param1[i] .getCanonicalType ();
5613
+ QualType T2 = Param2[i] .getCanonicalType ();
5589
5614
auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
5590
5615
auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
5591
5616
if (!TST1 || !TST2)
@@ -5644,8 +5669,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
5644
5669
// Any top-level cv-qualifiers modifying a parameter type are deleted when
5645
5670
// forming the function type.
5646
5671
for (unsigned i = 0 ; i < NumParams1; ++i)
5647
- if (!Context.hasSameUnqualifiedType (FD1->getParamDecl (i)->getType (),
5648
- FD2->getParamDecl (i)->getType ()))
5672
+ if (!Context.hasSameUnqualifiedType (Param1[i], Param2[i]))
5649
5673
return nullptr ;
5650
5674
5651
5675
// C++20 [temp.func.order]p6.3:
@@ -5733,8 +5757,8 @@ UnresolvedSetIterator Sema::getMostSpecialized(
5733
5757
FunctionTemplateDecl *Challenger
5734
5758
= cast<FunctionDecl>(*I)->getPrimaryTemplate ();
5735
5759
assert (Challenger && " Not a function template specialization?" );
5736
- if (isSameTemplate (getMoreSpecializedTemplate (BestTemplate, Challenger,
5737
- Loc, TPOC_Other, 0 , 0 ),
5760
+ if (isSameTemplate (getMoreSpecializedTemplate (BestTemplate, Challenger, Loc,
5761
+ TPOC_Other, 0 ),
5738
5762
Challenger)) {
5739
5763
Best = I;
5740
5764
BestTemplate = Challenger;
@@ -5749,7 +5773,7 @@ UnresolvedSetIterator Sema::getMostSpecialized(
5749
5773
= cast<FunctionDecl>(*I)->getPrimaryTemplate ();
5750
5774
if (I != Best &&
5751
5775
!isSameTemplate (getMoreSpecializedTemplate (BestTemplate, Challenger,
5752
- Loc, TPOC_Other, 0 , 0 ),
5776
+ Loc, TPOC_Other, 0 ),
5753
5777
BestTemplate)) {
5754
5778
Ambiguous = true ;
5755
5779
break ;
0 commit comments