Skip to content

Commit a520014

Browse files
zyn0217mattarde
authored andcommitted
[Clang] Recompute the value category when rebuilding SubstNonTypeTemplateParmExpr (llvm#172251)
In concept checking, we need to transform SubstNTTPExpr when evaluating constraints. The value category is initially computed during parameter mapping, possibly with a dependent expression. However during instantiation, it wasn't recomputed, and the stale category is propagated into parent expressions. So we may end up with an 'out-of-thin-air' reference type, which breaks the evaluation. We now call BuildSubstNonTypeTemplateParmExpr in TreeTransform, in which the value category is recomputed. The issue was brought by both 078e99e and the concept normalization patch, which are not released yet, so no release note. Fixes llvm#170856
1 parent a570eac commit a520014

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

clang/lib/Sema/TreeTransform.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4297,6 +4297,15 @@ class TreeTransform {
42974297
return getSema().OpenACC().ActOnOpenACCAsteriskSizeExpr(AsteriskLoc);
42984298
}
42994299

4300+
ExprResult
4301+
RebuildSubstNonTypeTemplateParmExpr(Decl *AssociatedDecl,
4302+
const NonTypeTemplateParmDecl *NTTP,
4303+
SourceLocation Loc, TemplateArgument Arg,
4304+
UnsignedOrNone PackIndex, bool Final) {
4305+
return getSema().BuildSubstNonTypeTemplateParmExpr(
4306+
AssociatedDecl, NTTP, Loc, Arg, PackIndex, Final);
4307+
}
4308+
43004309
private:
43014310
QualType TransformTypeInObjectScope(TypeLocBuilder &TLB, TypeLoc TL,
43024311
QualType ObjectType,
@@ -16467,7 +16476,7 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
1646716476

1646816477
TemplateArgument Pack = E->getArgumentPack();
1646916478
TemplateArgument Arg = SemaRef.getPackSubstitutedTemplateArgument(Pack);
16470-
return SemaRef.BuildSubstNonTypeTemplateParmExpr(
16479+
return getDerived().RebuildSubstNonTypeTemplateParmExpr(
1647116480
E->getAssociatedDecl(), E->getParameterPack(),
1647216481
E->getParameterPackLocation(), Arg, SemaRef.getPackIndex(Pack),
1647316482
E->getFinal());
@@ -16525,10 +16534,10 @@ ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
1652516534
Replacement = E->getReplacement();
1652616535
}
1652716536

16528-
return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
16529-
Replacement.get()->getType(), Replacement.get()->getValueKind(),
16530-
E->getNameLoc(), Replacement.get(), AssociatedDecl, E->getIndex(),
16531-
E->getPackIndex(), E->isReferenceParameter(), E->getFinal());
16537+
return getDerived().RebuildSubstNonTypeTemplateParmExpr(
16538+
AssociatedDecl, E->getParameter(), E->getNameLoc(),
16539+
TemplateArgument(Replacement.get(), /*IsCanonical=*/false),
16540+
E->getPackIndex(), E->getFinal());
1653216541
}
1653316542

1653416543
template<typename Derived>

clang/test/SemaTemplate/concepts.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,3 +1658,48 @@ struct {
16581658
void foo() { call(""); }
16591659

16601660
}
1661+
1662+
namespace GH170856 {
1663+
1664+
template <unsigned N, unsigned M> struct symbol_text {
1665+
consteval symbol_text(const char txt[]) {}
1666+
};
1667+
template <unsigned N> symbol_text(const char (&)[N]) -> symbol_text<1, 1>;
1668+
struct quantity_spec_interface_base {};
1669+
template <symbol_text, auto...> struct named_unit;
1670+
struct quantity_spec_interface : quantity_spec_interface_base {};
1671+
struct : quantity_spec_interface {
1672+
} thermodynamic_temperature;
1673+
1674+
template <typename T>
1675+
concept QuantitySpec = __is_convertible(T*, quantity_spec_interface_base*);
1676+
template <typename, auto QS>
1677+
concept QuantitySpecOf = QuantitySpec<decltype(QS)>;
1678+
template <typename T, auto QS>
1679+
concept PointOriginFor = QuantitySpecOf<decltype(QS), T::_quantity_spec_>;
1680+
1681+
template <symbol_text Symbol, auto QS, auto PO>
1682+
struct named_unit<Symbol, QS, PO> {
1683+
static constexpr auto _point_origin_ = PO;
1684+
};
1685+
template <auto QS> struct absolute_point_origin {
1686+
static constexpr auto _quantity_spec_ = QS;
1687+
};
1688+
template <auto> struct relative_point_origin {};
1689+
template <class R>
1690+
consteval PointOriginFor<R{}> auto default_point_origin(R) {
1691+
return R{}._point_origin_;
1692+
}
1693+
template <auto> class quantity_point;
1694+
template <class R> struct point_ {
1695+
quantity_point<default_point_origin(R{})> operator0();
1696+
};
1697+
template <auto R> point_<decltype(R)> point;
1698+
struct absolute_zero : absolute_point_origin<thermodynamic_temperature> {
1699+
} absolute_zero;
1700+
auto zeroth_kelvin = absolute_zero;
1701+
struct : named_unit<"", thermodynamic_temperature, zeroth_kelvin> {
1702+
} kelvin;
1703+
struct ice_point : relative_point_origin<point<kelvin>> {};
1704+
1705+
}

0 commit comments

Comments
 (0)