@@ -5333,38 +5333,37 @@ 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.
5345
- //
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);
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 ref-qualifier
5342
+ // of M is && or if M has no ref-qualifier and the positionally-corresponding
5343
+ // parameter of the other transformed template has rvalue reference type;
5344
+ // if this determination depends recursively upon whether X(M ) is an rvalue
5345
+ // reference type, it is not considered to have rvalue reference type.
5346
+ // - Otherwise, X(M ) is “lvalue reference to cv A”.
5347
+
5348
+ assert (Method && !Method->isExplicitObjectMemberFunction () &&
5349
+ " expected a member function with no explicit object parameter" );
5350
+
5351
+ RawType = Context.getQualifiedType (RawType, Method->getMethodQualifiers ());
5352
+ if (Method->getRefQualifier () == RQ_RValue ||
5353
+ (IsOtherRvr && Method->getRefQualifier () == RQ_None))
5354
+ return Context.getRValueReferenceType (RawType);
5355
+ return Context.getLValueReferenceType (RawType);
5357
5356
}
5358
5357
5359
5358
// / Determine whether the function template \p FT1 is at least as
5360
5359
// / specialized as \p FT2.
5361
- static bool isAtLeastAsSpecializedAs (Sema &S,
5362
- SourceLocation Loc,
5363
- FunctionTemplateDecl *FT1,
5364
- FunctionTemplateDecl *FT2,
5360
+ static bool isAtLeastAsSpecializedAs (Sema &S, SourceLocation Loc,
5361
+ const FunctionTemplateDecl *FT1,
5362
+ const FunctionTemplateDecl *FT2,
5365
5363
TemplatePartialOrderingContext TPOC,
5366
- unsigned NumCallArguments1,
5367
- bool Reversed) {
5364
+ bool Reversed,
5365
+ const SmallVector<QualType> &Args1,
5366
+ const SmallVector<QualType> &Args2) {
5368
5367
assert (!Reversed || TPOC == TPOC_Call);
5369
5368
5370
5369
FunctionDecl *FD1 = FT1->getTemplatedDecl ();
@@ -5381,74 +5380,15 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
5381
5380
// The types used to determine the ordering depend on the context in which
5382
5381
// the partial ordering is done:
5383
5382
TemplateDeductionInfo Info (Loc);
5384
- SmallVector<QualType, 4 > Args2;
5385
5383
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
-
5384
+ case TPOC_Call:
5444
5385
if (DeduceTemplateArguments (S, TemplateParams, Args2.data (), Args2.size (),
5445
5386
Args1.data (), Args1.size (), Info, Deduced,
5446
5387
TDF_None, /* PartialOrdering=*/ true ) !=
5447
5388
TemplateDeductionResult::Success)
5448
5389
return false ;
5449
5390
5450
5391
break ;
5451
- }
5452
5392
5453
5393
case TPOC_Conversion:
5454
5394
// - In the context of a call to a conversion operator, the return types
@@ -5536,8 +5476,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
5536
5476
// / \param NumCallArguments1 The number of arguments in the call to FT1, used
5537
5477
// / only when \c TPOC is \c TPOC_Call.
5538
5478
// /
5539
- // / \param NumCallArguments2 The number of arguments in the call to FT2, used
5540
- // / only when \c TPOC is \c TPOC_Call.
5479
+ // / \param RawObj1Ty The type of the object parameter of FT1 if a member
5480
+ // / function only used if \c TPOC is \c TPOC_Call and FT1 is a Function
5481
+ // / template from a member function
5482
+ // /
5483
+ // / \param RawObj2Ty The type of the object parameter of FT2 if a member
5484
+ // / function only used if \c TPOC is \c TPOC_Call and FT2 is a Function
5485
+ // / template from a member function
5541
5486
// /
5542
5487
// / \param Reversed If \c true, exactly one of FT1 and FT2 is an overload
5543
5488
// / candidate with a reversed parameter order. In this case, the corresponding
@@ -5548,13 +5493,76 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
5548
5493
FunctionTemplateDecl *Sema::getMoreSpecializedTemplate (
5549
5494
FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc,
5550
5495
TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1,
5551
- unsigned NumCallArguments2, bool Reversed) {
5496
+ QualType RawObj1Ty, QualType RawObj2Ty, bool Reversed) {
5497
+ SmallVector<QualType> Args1;
5498
+ SmallVector<QualType> Args2;
5499
+ const FunctionDecl *FD1 = FT1->getTemplatedDecl ();
5500
+ const FunctionDecl *FD2 = FT2->getTemplatedDecl ();
5501
+ bool shouldConvert1 = false ;
5502
+ bool shouldConvert2 = false ;
5503
+ QualType Obj1Ty;
5504
+ QualType Obj2Ty;
5505
+ if (TPOC == TPOC_Call) {
5506
+ const FunctionProtoType *Proto1 =
5507
+ FD1->getType ()->getAs <FunctionProtoType>();
5508
+ const FunctionProtoType *Proto2 =
5509
+ FD2->getType ()->getAs <FunctionProtoType>();
5552
5510
5553
- bool Better1 = isAtLeastAsSpecializedAs (*this , Loc, FT1, FT2, TPOC,
5554
- NumCallArguments1, Reversed);
5555
- bool Better2 = isAtLeastAsSpecializedAs (*this , Loc, FT2, FT1, TPOC,
5556
- NumCallArguments2, Reversed);
5511
+ // - In the context of a function call, the function parameter types are
5512
+ // used.
5513
+ const CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1);
5514
+ const CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2);
5515
+ // C++20 [temp.func.order]p3
5516
+ // [...] Each function template M that is a member function is
5517
+ // considered to have a new first parameter of type
5518
+ // X(M), described below, inserted in its function parameter list.
5519
+ //
5520
+ // Note that we interpret "that is a member function" as
5521
+ // "that is a member function with no expicit object argument".
5522
+ // Otherwise the ordering rules for methods with expicit objet arguments
5523
+ // against anything else make no sense.
5524
+ shouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction ();
5525
+ shouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction ();
5526
+ if (shouldConvert1) {
5527
+ bool isRValRef2 =
5528
+ shouldConvert2
5529
+ ? Method2->getRefQualifier () == RQ_RValue
5530
+ : Proto2->param_type_begin ()[0 ]->isRValueReferenceType ();
5531
+ // Compare 'this' from Method1 against first parameter from Method2.
5532
+ Obj1Ty = GetImplicitObjectParameterType (this ->Context , Method1, RawObj1Ty,
5533
+ isRValRef2);
5534
+ Args1.push_back (Obj1Ty);
5535
+ }
5536
+ if (shouldConvert2) {
5537
+ bool isRValRef1 =
5538
+ shouldConvert1
5539
+ ? Method1->getRefQualifier () == RQ_RValue
5540
+ : Proto1->param_type_begin ()[0 ]->isRValueReferenceType ();
5541
+ // Compare 'this' from Method2 against first parameter from Method1.
5542
+ Obj2Ty = GetImplicitObjectParameterType (this ->Context , Method2, RawObj2Ty,
5543
+ isRValRef1);
5544
+ Args2.push_back (Obj2Ty);
5545
+ }
5546
+ size_t NumComparedArguments = NumCallArguments1 + shouldConvert1;
5557
5547
5548
+ Args1.insert (Args1.end (), Proto1->param_type_begin (),
5549
+ Proto1->param_type_end ());
5550
+ Args2.insert (Args2.end (), Proto2->param_type_begin (),
5551
+ Proto2->param_type_end ());
5552
+
5553
+ // C++ [temp.func.order]p5:
5554
+ // The presence of unused ellipsis and default arguments has no effect on
5555
+ // the partial ordering of function templates.
5556
+ Args1.resize (std::min (Args1.size (), NumComparedArguments));
5557
+ Args2.resize (std::min (Args2.size (), NumComparedArguments));
5558
+
5559
+ if (Reversed)
5560
+ std::reverse (Args2.begin (), Args2.end ());
5561
+ }
5562
+ bool Better1 = isAtLeastAsSpecializedAs (*this , Loc, FT1, FT2, TPOC, Reversed,
5563
+ Args1, Args2);
5564
+ bool Better2 = isAtLeastAsSpecializedAs (*this , Loc, FT2, FT1, TPOC, Reversed,
5565
+ Args2, Args1);
5558
5566
// C++ [temp.deduct.partial]p10:
5559
5567
// F is more specialized than G if F is at least as specialized as G and G
5560
5568
// is not at least as specialized as F.
@@ -5568,12 +5576,28 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
5568
5576
// ... and if G has a trailing function parameter pack for which F does not
5569
5577
// have a corresponding parameter, and if F does not have a trailing
5570
5578
// 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 ();
5579
+
5580
+ SmallVector<QualType> param1;
5581
+ param1.reserve (FD1->param_size () + shouldConvert1);
5582
+ if (shouldConvert1)
5583
+ param1.push_back (Obj1Ty);
5584
+ for (const auto &x : FD1->parameters ())
5585
+ param1.push_back (x->getType ());
5586
+
5587
+ SmallVector<QualType> param2;
5588
+ param2.reserve (FD2->param_size () + shouldConvert2);
5589
+ if (shouldConvert2)
5590
+ param2.push_back (Obj2Ty);
5591
+ for (const auto &x : FD2->parameters ())
5592
+ param2.push_back (x->getType ());
5593
+
5594
+ unsigned NumParams1 = param1.size ();
5595
+ unsigned NumParams2 = param2.size ();
5596
+
5597
+ bool Variadic1 =
5598
+ FD1->param_size () && FD1->parameters ().back ()->isParameterPack ();
5599
+ bool Variadic2 =
5600
+ FD2->param_size () && FD2->parameters ().back ()->isParameterPack ();
5577
5601
if (Variadic1 != Variadic2) {
5578
5602
if (Variadic1 && NumParams1 > NumParams2)
5579
5603
return FT2;
@@ -5584,8 +5608,8 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
5584
5608
// This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
5585
5609
// there is no wording or even resolution for this issue.
5586
5610
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 ();
5611
+ QualType T1 = param1[i] .getCanonicalType ();
5612
+ QualType T2 = param2[i] .getCanonicalType ();
5589
5613
auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
5590
5614
auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
5591
5615
if (!TST1 || !TST2)
@@ -5644,8 +5668,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
5644
5668
// Any top-level cv-qualifiers modifying a parameter type are deleted when
5645
5669
// forming the function type.
5646
5670
for (unsigned i = 0 ; i < NumParams1; ++i)
5647
- if (!Context.hasSameUnqualifiedType (FD1->getParamDecl (i)->getType (),
5648
- FD2->getParamDecl (i)->getType ()))
5671
+ if (!Context.hasSameUnqualifiedType (param1[i], param2[i]))
5649
5672
return nullptr ;
5650
5673
5651
5674
// C++20 [temp.func.order]p6.3:
@@ -5733,8 +5756,8 @@ UnresolvedSetIterator Sema::getMostSpecialized(
5733
5756
FunctionTemplateDecl *Challenger
5734
5757
= cast<FunctionDecl>(*I)->getPrimaryTemplate ();
5735
5758
assert (Challenger && " Not a function template specialization?" );
5736
- if (isSameTemplate (getMoreSpecializedTemplate (BestTemplate, Challenger,
5737
- Loc, TPOC_Other, 0 , 0 ),
5759
+ if (isSameTemplate (getMoreSpecializedTemplate (BestTemplate, Challenger, Loc,
5760
+ TPOC_Other, 0 ),
5738
5761
Challenger)) {
5739
5762
Best = I;
5740
5763
BestTemplate = Challenger;
@@ -5749,7 +5772,7 @@ UnresolvedSetIterator Sema::getMostSpecialized(
5749
5772
= cast<FunctionDecl>(*I)->getPrimaryTemplate ();
5750
5773
if (I != Best &&
5751
5774
!isSameTemplate (getMoreSpecializedTemplate (BestTemplate, Challenger,
5752
- Loc, TPOC_Other, 0 , 0 ),
5775
+ Loc, TPOC_Other, 0 ),
5753
5776
BestTemplate)) {
5754
5777
Ambiguous = true ;
5755
5778
break ;
0 commit comments