@@ -1456,6 +1456,318 @@ class ASTVisitor
14561456 #endif
14571457 }
14581458
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+
14591771 std::string
14601772 extractName (
14611773 const NamedDecl* D)
@@ -3752,6 +4064,13 @@ buildTypeInfo(
37524064 ExtractionScope scope = enterMode (extract_mode);
37534065 // build the TypeInfo representation for the type
37544066 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+
37554074 Builder.Visit (qt);
37564075 return Builder.result ();
37574076}
0 commit comments