@@ -1456,6 +1456,318 @@ class ASTVisitor
1456
1456
#endif
1457
1457
}
1458
1458
1459
+ const NonTypeTemplateParmDecl*
1460
+ getNTTPFromExpr (
1461
+ const Expr* E,
1462
+ unsigned Depth)
1463
+ {
1464
+ while (true )
1465
+ {
1466
+ if (const auto * ICE = dyn_cast<ImplicitCastExpr>(E))
1467
+ {
1468
+ E = ICE->getSubExpr ();
1469
+ continue ;
1470
+ }
1471
+ if (const auto * CE = dyn_cast<ConstantExpr>(E))
1472
+ {
1473
+ E = CE->getSubExpr ();
1474
+ continue ;
1475
+ }
1476
+ if (const auto * SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
1477
+ {
1478
+ E = SNTTPE->getReplacement ();
1479
+ continue ;
1480
+ }
1481
+ if (const auto * CCE = dyn_cast<CXXConstructExpr>(E);
1482
+ CCE && CCE->getParenOrBraceRange ().isInvalid ())
1483
+ {
1484
+ // look through implicit copy construction from an lvalue of the same type
1485
+ E = CCE->getArg (0 );
1486
+ continue ;
1487
+ }
1488
+ break ;
1489
+ }
1490
+
1491
+ const auto * DRE = dyn_cast<DeclRefExpr>(E);
1492
+ if (! DRE)
1493
+ return nullptr ;
1494
+
1495
+ const auto * NTTPD = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl ());
1496
+ if (! NTTPD || NTTPD->getDepth () != Depth)
1497
+ return nullptr ;
1498
+
1499
+ return NTTPD;
1500
+ }
1501
+
1502
+ std::optional<TemplateArgument>
1503
+ tryGetTemplateArgument (
1504
+ TemplateParameterList* Parameters,
1505
+ ArrayRef<TemplateArgument> Arguments,
1506
+ unsigned Index)
1507
+ {
1508
+ if (Index == -1 )
1509
+ return std::nullopt;
1510
+ if (Index < Arguments.size ())
1511
+ return Arguments[Index];
1512
+ if (Parameters && Index < Parameters->size ())
1513
+ {
1514
+ NamedDecl* ND = Parameters->getParam (Index);
1515
+ if (auto * TTPD = dyn_cast<TemplateTypeParmDecl>(ND);
1516
+ TTPD && TTPD->hasDefaultArgument ())
1517
+ {
1518
+ return TTPD->getDefaultArgument ().getArgument ();
1519
+ }
1520
+ if (auto * NTTPD = dyn_cast<NonTypeTemplateParmDecl>(ND);
1521
+ NTTPD && NTTPD->hasDefaultArgument ())
1522
+ {
1523
+ return NTTPD->getDefaultArgument ().getArgument ();
1524
+ }
1525
+ }
1526
+ return std::nullopt;
1527
+ }
1528
+
1529
+ std::optional<std::tuple<TemplateParameterList*, llvm::SmallBitVector, unsigned >>
1530
+ isSFINAETemplate (
1531
+ TemplateDecl* TD,
1532
+ const IdentifierInfo* Member)
1533
+ {
1534
+ if (! TD)
1535
+ return std::nullopt;
1536
+
1537
+ auto FindParam = [this ](
1538
+ ArrayRef<TemplateArgument> Arguments,
1539
+ const TemplateArgument& Arg) -> unsigned
1540
+ {
1541
+ if (Arg.getKind () != TemplateArgument::Type)
1542
+ return -1 ;
1543
+ auto Found = std::ranges::find_if (Arguments, [&](const TemplateArgument& Other)
1544
+ {
1545
+ if (Other.getKind () != TemplateArgument::Type)
1546
+ return false ;
1547
+ return context_.hasSameType (Other.getAsType (), Arg.getAsType ());
1548
+ });
1549
+ return Found != Arguments.end () ? Found - Arguments.data () : -1 ;
1550
+ };
1551
+
1552
+ if (auto * ATD = dyn_cast<TypeAliasTemplateDecl>(TD))
1553
+ {
1554
+ auto Underlying = ATD->getTemplatedDecl ()->getUnderlyingType ();
1555
+ auto sfinae_info = getSFINAETemplate (Underlying, !Member);
1556
+ if (! sfinae_info)
1557
+ return std::nullopt;
1558
+ if (Member)
1559
+ sfinae_info->Member = Member;
1560
+ auto sfinae_result = isSFINAETemplate (
1561
+ sfinae_info->Template , sfinae_info->Member );
1562
+ if (! sfinae_result)
1563
+ return std::nullopt;
1564
+ auto [template_params, controlling_params, param_idx] = *sfinae_result;
1565
+ auto param_arg = tryGetTemplateArgument (
1566
+ template_params, sfinae_info->Arguments , param_idx);
1567
+ if (! param_arg)
1568
+ return std::nullopt;
1569
+ unsigned ParamIdx = FindParam (ATD->getInjectedTemplateArgs (), *param_arg);
1570
+ return std::make_tuple (ATD->getTemplateParameters (), std::move (controlling_params), ParamIdx);
1571
+ }
1572
+
1573
+ auto * CTD = dyn_cast<ClassTemplateDecl>(TD);
1574
+ if (! CTD)
1575
+ return std::nullopt;
1576
+
1577
+ auto PrimaryArgs = CTD->getInjectedTemplateArgs ();
1578
+ llvm::SmallBitVector ControllingParams (PrimaryArgs.size ());
1579
+
1580
+ QualType MemberType;
1581
+ unsigned ParamIdx = -1 ;
1582
+ auto IsMismatch = [&](CXXRecordDecl* RD, ArrayRef<TemplateArgument> Args)
1583
+ {
1584
+ if (! RD->hasDefinition ())
1585
+ return false ;
1586
+ auto MemberLookup = RD->lookup (Member);
1587
+ QualType CurrentType;
1588
+ if (MemberLookup.empty ())
1589
+ {
1590
+ if (! RD->getNumBases ())
1591
+ return false ;
1592
+ for (auto & Base : RD->bases ())
1593
+ {
1594
+ auto sfinae_info = getSFINAETemplate (Base.getType (), false );
1595
+ if (! sfinae_info)
1596
+ {
1597
+ // if the base is an opaque dependent type, we can't determine
1598
+ // whether it's a SFINAE type
1599
+ if (Base.getType ()->isDependentType ())
1600
+ return true ;
1601
+ continue ;
1602
+ }
1603
+ auto sfinae_result = isSFINAETemplate (
1604
+ sfinae_info->Template , Member);
1605
+ if (! sfinae_result)
1606
+ return true ;
1607
+
1608
+ auto [template_params, controlling_params, param_idx] = *sfinae_result;
1609
+ auto param_arg = tryGetTemplateArgument (
1610
+ template_params, sfinae_info->Arguments , param_idx);
1611
+ if (! param_arg)
1612
+ return true ;
1613
+ auto CurrentTypeFromBase = param_arg->getAsType ();
1614
+ if (CurrentType.isNull ())
1615
+ CurrentType = CurrentTypeFromBase;
1616
+ else if (! context_.hasSameType (CurrentType, CurrentTypeFromBase))
1617
+ return true ;
1618
+ }
1619
+ // didn't find a base that defines the specified member
1620
+ if (CurrentType.isNull ())
1621
+ return false ;
1622
+ }
1623
+ else
1624
+ {
1625
+ // ambiguous lookup
1626
+ if (! MemberLookup.isSingleResult ())
1627
+ return true ;
1628
+ if (auto * TND = dyn_cast<TypedefNameDecl>(MemberLookup.front ()))
1629
+ CurrentType = TND->getUnderlyingType ();
1630
+ else
1631
+ // the specialization has a member with the right name,
1632
+ // but it isn't an alias declaration/typedef declaration...
1633
+ return true ;
1634
+ }
1635
+
1636
+ #if 0
1637
+ if(! CurrentType->isDependentType())
1638
+ return ! context_.hasSameType(MemberType, CurrentType);
1639
+
1640
+ auto FoundIdx = FindParam(Args, TemplateArgument(CurrentType));
1641
+ if(ParamIdx != -1 && FoundIdx != ParamIdx)
1642
+ return true;
1643
+
1644
+ ParamIdx = FoundIdx;
1645
+ #endif
1646
+
1647
+ if (CurrentType->isDependentType ())
1648
+ {
1649
+ auto FoundIdx = FindParam (Args, TemplateArgument (CurrentType));
1650
+ if (FoundIdx == -1 || FoundIdx >= PrimaryArgs.size ())
1651
+ return true ;
1652
+ ParamIdx = FoundIdx;
1653
+ TemplateArgument MappedPrimary = PrimaryArgs[FoundIdx];
1654
+ assert (MappedPrimary.getKind () == TemplateArgument::Type);
1655
+ CurrentType = MappedPrimary.getAsType ();
1656
+ }
1657
+
1658
+ if (MemberType.isNull ())
1659
+ MemberType = CurrentType;
1660
+
1661
+ return ! context_.hasSameType (MemberType, CurrentType);
1662
+ };
1663
+
1664
+ if (IsMismatch (CTD->getTemplatedDecl (), PrimaryArgs))
1665
+ return std::nullopt;
1666
+
1667
+ for (auto * CTSD : CTD->specializations ())
1668
+ {
1669
+ if (CTSD->isExplicitSpecialization () &&
1670
+ IsMismatch (CTSD, CTSD->getTemplateArgs ().asArray ()))
1671
+ return std::nullopt;
1672
+ }
1673
+
1674
+ SmallVector<ClassTemplatePartialSpecializationDecl*> PartialSpecs;
1675
+ CTD->getPartialSpecializations (PartialSpecs);
1676
+
1677
+ for (auto * CTPSD : PartialSpecs)
1678
+ {
1679
+ auto PartialArgs = CTPSD->getTemplateArgs ().asArray ();
1680
+ if (IsMismatch (CTPSD, PartialArgs))
1681
+ return std::nullopt;
1682
+ for (std::size_t I = 0 ; I < PartialArgs.size (); ++I)
1683
+ {
1684
+ TemplateArgument Arg = PartialArgs[I];
1685
+ switch (Arg.getKind ())
1686
+ {
1687
+ case TemplateArgument::Integral:
1688
+ case TemplateArgument::Declaration:
1689
+ case TemplateArgument::StructuralValue:
1690
+ case TemplateArgument::NullPtr:
1691
+ break ;
1692
+ case TemplateArgument::Expression:
1693
+ if (getNTTPFromExpr (
1694
+ Arg.getAsExpr (),
1695
+ CTPSD->getTemplateDepth () - 1 ))
1696
+ continue ;
1697
+ break ;
1698
+ default :
1699
+ continue ;
1700
+ }
1701
+ ControllingParams.set (I);
1702
+ // .getAsExpr()
1703
+ }
1704
+ }
1705
+
1706
+ return std::make_tuple (CTD->getTemplateParameters (), std::move (ControllingParams), ParamIdx);
1707
+ }
1708
+
1709
+ struct SFINAEInfo
1710
+ {
1711
+ TemplateDecl* Template = nullptr ;
1712
+ const IdentifierInfo* Member = nullptr ;
1713
+ ArrayRef<TemplateArgument> Arguments;
1714
+ };
1715
+
1716
+ std::optional<SFINAEInfo>
1717
+ getSFINAETemplate (QualType T, bool AllowDependentNames)
1718
+ {
1719
+ assert (!T.isNull ());
1720
+ SFINAEInfo SFINAE;
1721
+ if (auto * ET = T->getAs <ElaboratedType>())
1722
+ T = ET->getNamedType ();
1723
+
1724
+ if (auto * DNT = T->getAsAdjusted <DependentNameType>();
1725
+ DNT && AllowDependentNames)
1726
+ {
1727
+ SFINAE.Member = DNT->getIdentifier ();
1728
+ T = QualType (DNT->getQualifier ()->getAsType (), 0 );
1729
+ }
1730
+
1731
+ if (auto * TST = T->getAsAdjusted <TemplateSpecializationType>())
1732
+ {
1733
+ SFINAE.Template = TST->getTemplateName ().getAsTemplateDecl ();
1734
+ SFINAE.Arguments = TST->template_arguments ();
1735
+ return SFINAE;
1736
+ }
1737
+ return std::nullopt;
1738
+ }
1739
+
1740
+ std::optional<std::pair<QualType, std::vector<TemplateArgument>>>
1741
+ isSFINAEType (QualType T)
1742
+ {
1743
+ auto sfinae_info = getSFINAETemplate (T, true );
1744
+ if (! sfinae_info)
1745
+ return std::nullopt;
1746
+
1747
+ auto sfinae_result = isSFINAETemplate (
1748
+ sfinae_info->Template , sfinae_info->Member );
1749
+
1750
+ if (! sfinae_result)
1751
+ return std::nullopt;
1752
+
1753
+ auto [template_params, controlling_params, param_idx] = *sfinae_result;
1754
+
1755
+ auto Args = sfinae_info->Arguments ;
1756
+ auto param_arg = tryGetTemplateArgument (
1757
+ template_params, Args, param_idx);
1758
+ if (! param_arg)
1759
+ return std::nullopt;
1760
+
1761
+ std::vector<TemplateArgument> ControllingArgs;
1762
+ for (std::size_t I = 0 ; I < Args.size (); ++I)
1763
+ {
1764
+ if (controlling_params[I])
1765
+ ControllingArgs.emplace_back (Args[I]);
1766
+ }
1767
+
1768
+ return std::make_pair (param_arg->getAsType (), std::move (ControllingArgs));
1769
+ }
1770
+
1459
1771
std::string
1460
1772
extractName (
1461
1773
const NamedDecl* D)
@@ -3752,6 +4064,13 @@ buildTypeInfo(
3752
4064
ExtractionScope scope = enterMode (extract_mode);
3753
4065
// build the TypeInfo representation for the type
3754
4066
TypeInfoBuilder Builder (*this );
4067
+
4068
+ if (config_->detectSfinae )
4069
+ {
4070
+ if (auto SFINAE = isSFINAEType (qt); SFINAE.has_value ())
4071
+ qt = SFINAE->first .withFastQualifiers (qt.getLocalFastQualifiers ());
4072
+ }
4073
+
3755
4074
Builder.Visit (qt);
3756
4075
return Builder.result ();
3757
4076
}
0 commit comments